mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			583 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			583 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef C4_DUMP_HPP_
 | |
| #define C4_DUMP_HPP_
 | |
| 
 | |
| #include <c4/substr.hpp>
 | |
| 
 | |
| namespace c4 {
 | |
| 
 | |
| C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| /** type of the function to dump characters */
 | |
| using DumperPfn = void (*)(csubstr buf);
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| template<DumperPfn dumpfn, class Arg>
 | |
| inline size_t dump(substr buf, Arg const& a)
 | |
| {
 | |
|     size_t sz = to_chars(buf, a); // need to serialize to the buffer
 | |
|     if(C4_LIKELY(sz <= buf.len))
 | |
|         dumpfn(buf.first(sz));
 | |
|     return sz;
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class Arg>
 | |
| inline size_t dump(DumperFn &&dumpfn, substr buf, Arg const& a)
 | |
| {
 | |
|     size_t sz = to_chars(buf, a); // need to serialize to the buffer
 | |
|     if(C4_LIKELY(sz <= buf.len))
 | |
|         dumpfn(buf.first(sz));
 | |
|     return sz;
 | |
| }
 | |
| 
 | |
| template<DumperPfn dumpfn>
 | |
| inline size_t dump(substr buf, csubstr a)
 | |
| {
 | |
|     if(buf.len)
 | |
|         dumpfn(a); // dump directly, no need to serialize to the buffer
 | |
|     return 0; // no space was used in the buffer
 | |
| }
 | |
| 
 | |
| template<class DumperFn>
 | |
| inline size_t dump(DumperFn &&dumpfn, substr buf, csubstr a)
 | |
| {
 | |
|     if(buf.len)
 | |
|         dumpfn(a); // dump directly, no need to serialize to the buffer
 | |
|     return 0; // no space was used in the buffer
 | |
| }
 | |
| 
 | |
| template<DumperPfn dumpfn, size_t N>
 | |
| inline size_t dump(substr buf, const char (&a)[N])
 | |
| {
 | |
|     if(buf.len)
 | |
|         dumpfn(csubstr(a)); // dump directly, no need to serialize to the buffer
 | |
|     return 0; // no space was used in the buffer
 | |
| }
 | |
| 
 | |
| template<class DumperFn, size_t N>
 | |
| inline size_t dump(DumperFn &&dumpfn, substr buf, const char (&a)[N])
 | |
| {
 | |
|     if(buf.len)
 | |
|         dumpfn(csubstr(a)); // dump directly, no need to serialize to the buffer
 | |
|     return 0; // no space was used in the buffer
 | |
| }
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| /** */
 | |
| struct DumpResults
 | |
| {
 | |
|     enum : size_t { noarg = (size_t)-1 };
 | |
|     size_t bufsize = 0;
 | |
|     size_t lastok = noarg;
 | |
|     bool success_until(size_t expected) const { return lastok == noarg ? false : lastok >= expected; }
 | |
|     bool write_arg(size_t arg) const { return lastok == noarg || arg > lastok; }
 | |
|     size_t argfail() const { return lastok + 1; }
 | |
| };
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| /// @cond dev
 | |
| // terminates the variadic recursion
 | |
| template<class DumperFn>
 | |
| size_t cat_dump(DumperFn &&, substr)
 | |
| {
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| // terminates the variadic recursion
 | |
| template<DumperPfn dumpfn>
 | |
| size_t cat_dump(substr)
 | |
| {
 | |
|     return 0;
 | |
| }
 | |
| /// @endcond
 | |
| 
 | |
| /** take the function pointer as a function argument */
 | |
| template<class DumperFn, class Arg, class... Args>
 | |
| size_t cat_dump(DumperFn &&dumpfn, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     size_t size_for_a = dump(dumpfn, buf, a);
 | |
|     if(C4_UNLIKELY(size_for_a > buf.len))
 | |
|         buf = buf.first(0); // ensure no more calls
 | |
|     size_t size_for_more = cat_dump(dumpfn, buf, more...);
 | |
|     return size_for_more > size_for_a ? size_for_more : size_for_a;
 | |
| }
 | |
| 
 | |
| /** take the function pointer as a template argument */
 | |
| template<DumperPfn dumpfn,class Arg, class... Args>
 | |
| size_t cat_dump(substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     size_t size_for_a = dump<dumpfn>(buf, a);
 | |
|     if(C4_LIKELY(size_for_a > buf.len))
 | |
|         buf = buf.first(0); // ensure no more calls
 | |
|     size_t size_for_more = cat_dump<dumpfn>(buf, more...);
 | |
|     return size_for_more > size_for_a ? size_for_more : size_for_a;
 | |
| }
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| /// @cond dev
 | |
| namespace detail {
 | |
| 
 | |
| // terminates the variadic recursion
 | |
| template<DumperPfn dumpfn, class Arg>
 | |
| DumpResults cat_dump_resume(size_t currarg, DumpResults results, substr buf, Arg const& C4_RESTRICT a)
 | |
| {
 | |
|     if(C4_LIKELY(results.write_arg(currarg)))
 | |
|     {
 | |
|         size_t sz = dump<dumpfn>(buf, a);  // yield to the specialized function
 | |
|         if(currarg == results.lastok + 1 && sz <= buf.len)
 | |
|             results.lastok = currarg;
 | |
|         results.bufsize = sz > results.bufsize ? sz : results.bufsize;
 | |
|     }
 | |
|     return results;
 | |
| }
 | |
| 
 | |
| // terminates the variadic recursion
 | |
| template<class DumperFn, class Arg>
 | |
| DumpResults cat_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults results, substr buf, Arg const& C4_RESTRICT a)
 | |
| {
 | |
|     if(C4_LIKELY(results.write_arg(currarg)))
 | |
|     {
 | |
|         size_t sz = dump(dumpfn, buf, a);  // yield to the specialized function
 | |
|         if(currarg == results.lastok + 1 && sz <= buf.len)
 | |
|             results.lastok = currarg;
 | |
|         results.bufsize = sz > results.bufsize ? sz : results.bufsize;
 | |
|     }
 | |
|     return results;
 | |
| }
 | |
| 
 | |
| template<DumperPfn dumpfn, class Arg, class... Args>
 | |
| DumpResults cat_dump_resume(size_t currarg, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     results = detail::cat_dump_resume<dumpfn>(currarg, results, buf, a);
 | |
|     return detail::cat_dump_resume<dumpfn>(currarg + 1u, results, buf, more...);
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class Arg, class... Args>
 | |
| DumpResults cat_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     results = detail::cat_dump_resume(currarg, dumpfn, results, buf, a);
 | |
|     return detail::cat_dump_resume(currarg + 1u, dumpfn, results, buf, more...);
 | |
| }
 | |
| } // namespace detail
 | |
| /// @endcond
 | |
| 
 | |
| 
 | |
| template<DumperPfn dumpfn, class Arg, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults cat_dump_resume(DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     if(results.bufsize > buf.len)
 | |
|         return results;
 | |
|     return detail::cat_dump_resume<dumpfn>(0u, results, buf, a, more...);
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class Arg, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults cat_dump_resume(DumperFn &&dumpfn, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     if(results.bufsize > buf.len)
 | |
|         return results;
 | |
|     return detail::cat_dump_resume(0u, dumpfn, results, buf, a, more...);
 | |
| }
 | |
| 
 | |
| template<DumperPfn dumpfn, class Arg, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults cat_dump_resume(substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     return detail::cat_dump_resume<dumpfn>(0u, DumpResults{}, buf, a, more...);
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class Arg, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults cat_dump_resume(DumperFn &&dumpfn, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     return detail::cat_dump_resume(0u, dumpfn, DumpResults{}, buf, a, more...);
 | |
| }
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| /// @cond dev
 | |
| // terminate the recursion
 | |
| template<class DumperFn, class Sep>
 | |
| size_t catsep_dump(DumperFn &&, substr, Sep const& C4_RESTRICT)
 | |
| {
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| // terminate the recursion
 | |
| template<DumperPfn dumpfn, class Sep>
 | |
| size_t catsep_dump(substr, Sep const& C4_RESTRICT)
 | |
| {
 | |
|     return 0;
 | |
| }
 | |
| /// @endcond
 | |
| 
 | |
| /** take the function pointer as a function argument */
 | |
| template<class DumperFn, class Sep, class Arg, class... Args>
 | |
| size_t catsep_dump(DumperFn &&dumpfn, substr buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     size_t sz = dump(dumpfn, buf, a);
 | |
|     if(C4_UNLIKELY(sz > buf.len))
 | |
|         buf = buf.first(0); // ensure no more calls
 | |
|     if C4_IF_CONSTEXPR (sizeof...(more) > 0)
 | |
|     {
 | |
|         size_t szsep = dump(dumpfn, buf, sep);
 | |
|         if(C4_UNLIKELY(szsep > buf.len))
 | |
|             buf = buf.first(0); // ensure no more calls
 | |
|         sz = sz > szsep ? sz : szsep;
 | |
|     }
 | |
|     size_t size_for_more = catsep_dump(dumpfn, buf, sep, more...);
 | |
|     return size_for_more > sz ? size_for_more : sz;
 | |
| }
 | |
| 
 | |
| /** take the function pointer as a template argument */
 | |
| template<DumperPfn dumpfn, class Sep, class Arg, class... Args>
 | |
| size_t catsep_dump(substr buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     size_t sz = dump<dumpfn>(buf, a);
 | |
|     if(C4_UNLIKELY(sz > buf.len))
 | |
|         buf = buf.first(0); // ensure no more calls
 | |
|     if C4_IF_CONSTEXPR (sizeof...(more) > 0)
 | |
|     {
 | |
|         size_t szsep = dump<dumpfn>(buf, sep);
 | |
|         if(C4_UNLIKELY(szsep > buf.len))
 | |
|             buf = buf.first(0); // ensure no more calls
 | |
|         sz = sz > szsep ? sz : szsep;
 | |
|     }
 | |
|     size_t size_for_more = catsep_dump<dumpfn>(buf, sep, more...);
 | |
|     return size_for_more > sz ? size_for_more : sz;
 | |
| }
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| /// @cond dev
 | |
| namespace detail {
 | |
| template<DumperPfn dumpfn, class Arg>
 | |
| void catsep_dump_resume_(size_t currarg, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Arg const& C4_RESTRICT a)
 | |
| {
 | |
|     if(C4_LIKELY(results->write_arg(currarg)))
 | |
|     {
 | |
|         size_t sz = dump<dumpfn>(*buf, a);
 | |
|         results->bufsize = sz > results->bufsize ? sz : results->bufsize;
 | |
|         if(C4_LIKELY(sz <= buf->len))
 | |
|             results->lastok = currarg;
 | |
|         else
 | |
|             buf->len = 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class Arg>
 | |
| void catsep_dump_resume_(size_t currarg, DumperFn &&dumpfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Arg const& C4_RESTRICT a)
 | |
| {
 | |
|     if(C4_LIKELY(results->write_arg(currarg)))
 | |
|     {
 | |
|         size_t sz = dump(dumpfn, *buf, a);
 | |
|         results->bufsize = sz > results->bufsize ? sz : results->bufsize;
 | |
|         if(C4_LIKELY(sz <= buf->len))
 | |
|             results->lastok = currarg;
 | |
|         else
 | |
|             buf->len = 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| template<DumperPfn dumpfn, class Sep, class Arg>
 | |
| C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& C4_RESTRICT, Arg const& C4_RESTRICT a)
 | |
| {
 | |
|     detail::catsep_dump_resume_<dumpfn>(currarg, results, buf, a);
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class Sep, class Arg>
 | |
| C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& C4_RESTRICT, Arg const& C4_RESTRICT a)
 | |
| {
 | |
|     detail::catsep_dump_resume_(currarg, dumpfn, results, buf, a);
 | |
| }
 | |
| 
 | |
| template<DumperPfn dumpfn, class Sep, class Arg, class... Args>
 | |
| C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     detail::catsep_dump_resume_<dumpfn>(currarg     , results, buf, a);
 | |
|     detail::catsep_dump_resume_<dumpfn>(currarg + 1u, results, buf, sep);
 | |
|     detail::catsep_dump_resume <dumpfn>(currarg + 2u, results, buf, sep, more...);
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class Sep, class Arg, class... Args>
 | |
| C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     detail::catsep_dump_resume_(currarg     , dumpfn, results, buf, a);
 | |
|     detail::catsep_dump_resume_(currarg + 1u, dumpfn, results, buf, sep);
 | |
|     detail::catsep_dump_resume (currarg + 2u, dumpfn, results, buf, sep, more...);
 | |
| }
 | |
| } // namespace detail
 | |
| /// @endcond
 | |
| 
 | |
| 
 | |
| template<DumperPfn dumpfn, class Sep, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults catsep_dump_resume(DumpResults results, substr buf, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     detail::catsep_dump_resume<dumpfn>(0u, &results, &buf, sep, more...);
 | |
|     return results;
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class Sep, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults catsep_dump_resume(DumperFn &&dumpfn, DumpResults results, substr buf, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     detail::catsep_dump_resume(0u, dumpfn, &results, &buf, sep, more...);
 | |
|     return results;
 | |
| }
 | |
| 
 | |
| template<DumperPfn dumpfn, class Sep, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults catsep_dump_resume(substr buf, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     DumpResults results;
 | |
|     detail::catsep_dump_resume<dumpfn>(0u, &results, &buf, sep, more...);
 | |
|     return results;
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class Sep, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults catsep_dump_resume(DumperFn &&dumpfn, substr buf, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     DumpResults results;
 | |
|     detail::catsep_dump_resume(0u, dumpfn, &results, &buf, sep, more...);
 | |
|     return results;
 | |
| }
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| /** take the function pointer as a function argument */
 | |
| template<class DumperFn>
 | |
| C4_ALWAYS_INLINE size_t format_dump(DumperFn &&dumpfn, substr buf, csubstr fmt)
 | |
| {
 | |
|     // we can dump without using buf
 | |
|     // but we'll only dump if the buffer is ok
 | |
|     if(C4_LIKELY(buf.len > 0 && fmt.len))
 | |
|         dumpfn(fmt);
 | |
|     return 0u;
 | |
| }
 | |
| 
 | |
| /** take the function pointer as a function argument */
 | |
| template<DumperPfn dumpfn>
 | |
| C4_ALWAYS_INLINE size_t format_dump(substr buf, csubstr fmt)
 | |
| {
 | |
|     // we can dump without using buf
 | |
|     // but we'll only dump if the buffer is ok
 | |
|     if(C4_LIKELY(buf.len > 0 && fmt.len > 0))
 | |
|         dumpfn(fmt);
 | |
|     return 0u;
 | |
| }
 | |
| 
 | |
| /** take the function pointer as a function argument */
 | |
| template<class DumperFn, class Arg, class... Args>
 | |
| size_t format_dump(DumperFn &&dumpfn, substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     // we can dump without using buf
 | |
|     // but we'll only dump if the buffer is ok
 | |
|     size_t pos = fmt.find("{}"); // @todo use _find_fmt()
 | |
|     if(C4_UNLIKELY(pos == csubstr::npos))
 | |
|     {
 | |
|         if(C4_LIKELY(buf.len > 0 && fmt.len > 0))
 | |
|             dumpfn(fmt);
 | |
|         return 0u;
 | |
|     }
 | |
|     if(C4_LIKELY(buf.len > 0 && pos > 0))
 | |
|         dumpfn(fmt.first(pos)); // we can dump without using buf
 | |
|     fmt = fmt.sub(pos + 2); // skip {} do this before assigning to pos again
 | |
|     pos = dump(dumpfn, buf, a);
 | |
|     if(C4_UNLIKELY(pos > buf.len))
 | |
|         buf.len = 0; // ensure no more calls to dump
 | |
|     size_t size_for_more = format_dump(dumpfn, buf, fmt, more...);
 | |
|     return size_for_more > pos ? size_for_more : pos;
 | |
| }
 | |
| 
 | |
| /** take the function pointer as a template argument */
 | |
| template<DumperPfn dumpfn, class Arg, class... Args>
 | |
| size_t format_dump(substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     // we can dump without using buf
 | |
|     // but we'll only dump if the buffer is ok
 | |
|     size_t pos = fmt.find("{}"); // @todo use _find_fmt()
 | |
|     if(C4_UNLIKELY(pos == csubstr::npos))
 | |
|     {
 | |
|         if(C4_LIKELY(buf.len > 0 && fmt.len > 0))
 | |
|             dumpfn(fmt);
 | |
|         return 0u;
 | |
|     }
 | |
|     if(C4_LIKELY(buf.len > 0 && pos > 0))
 | |
|         dumpfn(fmt.first(pos)); // we can dump without using buf
 | |
|     fmt = fmt.sub(pos + 2); // skip {} do this before assigning to pos again
 | |
|     pos = dump<dumpfn>(buf, a);
 | |
|     if(C4_UNLIKELY(pos > buf.len))
 | |
|         buf.len = 0; // ensure no more calls to dump
 | |
|     size_t size_for_more = format_dump<dumpfn>(buf, fmt, more...);
 | |
|     return size_for_more > pos ? size_for_more : pos;
 | |
| }
 | |
| 
 | |
| 
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| /// @cond dev
 | |
| namespace detail {
 | |
| 
 | |
| template<DumperPfn dumpfn>
 | |
| DumpResults format_dump_resume(size_t currarg, DumpResults results, substr buf, csubstr fmt)
 | |
| {
 | |
|     // we can dump without using buf
 | |
|     // but we'll only dump if the buffer is ok
 | |
|     if(C4_LIKELY(buf.len > 0))
 | |
|     {
 | |
|         dumpfn(fmt);
 | |
|         results.lastok = currarg;
 | |
|     }
 | |
|     return results;
 | |
| }
 | |
| 
 | |
| template<class DumperFn>
 | |
| DumpResults format_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults results, substr buf, csubstr fmt)
 | |
| {
 | |
|     // we can dump without using buf
 | |
|     // but we'll only dump if the buffer is ok
 | |
|     if(C4_LIKELY(buf.len > 0))
 | |
|     {
 | |
|         dumpfn(fmt);
 | |
|         results.lastok = currarg;
 | |
|     }
 | |
|     return results;
 | |
| }
 | |
| 
 | |
| template<DumperPfn dumpfn, class Arg, class... Args>
 | |
| DumpResults format_dump_resume(size_t currarg, DumpResults results, substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     // we need to process the format even if we're not
 | |
|     // going to print the first arguments because we're resuming
 | |
|     size_t pos = fmt.find("{}"); // @todo use _find_fmt()
 | |
|     // we can dump without using buf
 | |
|     // but we'll only dump if the buffer is ok
 | |
|     if(C4_LIKELY(results.write_arg(currarg)))
 | |
|     {
 | |
|         if(C4_UNLIKELY(pos == csubstr::npos))
 | |
|         {
 | |
|             if(C4_LIKELY(buf.len > 0))
 | |
|             {
 | |
|                 results.lastok = currarg;
 | |
|                 dumpfn(fmt);
 | |
|             }
 | |
|             return results;
 | |
|         }
 | |
|         if(C4_LIKELY(buf.len > 0))
 | |
|         {
 | |
|             results.lastok = currarg;
 | |
|             dumpfn(fmt.first(pos));
 | |
|         }
 | |
|     }
 | |
|     fmt = fmt.sub(pos + 2);
 | |
|     if(C4_LIKELY(results.write_arg(currarg + 1)))
 | |
|     {
 | |
|         pos = dump<dumpfn>(buf, a);
 | |
|         results.bufsize = pos > results.bufsize ? pos : results.bufsize;
 | |
|         if(C4_LIKELY(pos <= buf.len))
 | |
|             results.lastok = currarg + 1;
 | |
|         else
 | |
|             buf.len = 0;
 | |
|     }
 | |
|     return detail::format_dump_resume<dumpfn>(currarg + 2u, results, buf, fmt, more...);
 | |
| }
 | |
| /// @endcond
 | |
| 
 | |
| 
 | |
| template<class DumperFn, class Arg, class... Args>
 | |
| DumpResults format_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults results, substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     // we need to process the format even if we're not
 | |
|     // going to print the first arguments because we're resuming
 | |
|     size_t pos = fmt.find("{}"); // @todo use _find_fmt()
 | |
|     // we can dump without using buf
 | |
|     // but we'll only dump if the buffer is ok
 | |
|     if(C4_LIKELY(results.write_arg(currarg)))
 | |
|     {
 | |
|         if(C4_UNLIKELY(pos == csubstr::npos))
 | |
|         {
 | |
|             if(C4_LIKELY(buf.len > 0))
 | |
|             {
 | |
|                 results.lastok = currarg;
 | |
|                 dumpfn(fmt);
 | |
|             }
 | |
|             return results;
 | |
|         }
 | |
|         if(C4_LIKELY(buf.len > 0))
 | |
|         {
 | |
|             results.lastok = currarg;
 | |
|             dumpfn(fmt.first(pos));
 | |
|         }
 | |
|     }
 | |
|     fmt = fmt.sub(pos + 2);
 | |
|     if(C4_LIKELY(results.write_arg(currarg + 1)))
 | |
|     {
 | |
|         pos = dump(dumpfn, buf, a);
 | |
|         results.bufsize = pos > results.bufsize ? pos : results.bufsize;
 | |
|         if(C4_LIKELY(pos <= buf.len))
 | |
|             results.lastok = currarg + 1;
 | |
|         else
 | |
|             buf.len = 0;
 | |
|     }
 | |
|     return detail::format_dump_resume(currarg + 2u, dumpfn, results, buf, fmt, more...);
 | |
| }
 | |
| } // namespace detail
 | |
| 
 | |
| 
 | |
| template<DumperPfn dumpfn, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults format_dump_resume(DumpResults results, substr buf, csubstr fmt, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     return detail::format_dump_resume<dumpfn>(0u, results, buf, fmt, more...);
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults format_dump_resume(DumperFn &&dumpfn, DumpResults results, substr buf, csubstr fmt, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     return detail::format_dump_resume(0u, dumpfn, results, buf, fmt, more...);
 | |
| }
 | |
| 
 | |
| 
 | |
| template<DumperPfn dumpfn, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults format_dump_resume(substr buf, csubstr fmt, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     return detail::format_dump_resume<dumpfn>(0u, DumpResults{}, buf, fmt, more...);
 | |
| }
 | |
| 
 | |
| template<class DumperFn, class... Args>
 | |
| C4_ALWAYS_INLINE DumpResults format_dump_resume(DumperFn &&dumpfn, substr buf, csubstr fmt, Args const& C4_RESTRICT ...more)
 | |
| {
 | |
|     return detail::format_dump_resume(0u, dumpfn, DumpResults{}, buf, fmt, more...);
 | |
| }
 | |
| 
 | |
| C4_SUPPRESS_WARNING_GCC_CLANG_POP
 | |
| 
 | |
| } // namespace c4
 | |
| 
 | |
| 
 | |
| #endif /* C4_DUMP_HPP_ */
 | 
