writer.hpp (5440B)
1 #ifndef _C4_YML_WRITER_HPP_ 2 #define _C4_YML_WRITER_HPP_ 3 4 #ifndef _C4_YML_COMMON_HPP_ 5 #include "./common.hpp" 6 #endif 7 8 #include <c4/substr.hpp> 9 #include <stdio.h> // fwrite(), fputc() 10 #include <string.h> // memcpy() 11 12 13 namespace c4 { 14 namespace yml { 15 16 17 /** Repeat-Character: a character to be written a number of times. */ 18 struct RepC 19 { 20 char c; 21 size_t num_times; 22 }; 23 inline RepC indent_to(size_t num_levels) 24 { 25 return {' ', size_t(2) * num_levels}; 26 } 27 28 29 //----------------------------------------------------------------------------- 30 //----------------------------------------------------------------------------- 31 //----------------------------------------------------------------------------- 32 /** A writer that outputs to a file. Defaults to stdout. */ 33 struct WriterFile 34 { 35 FILE * m_file; 36 size_t m_pos; 37 38 WriterFile(FILE *f = nullptr) : m_file(f ? f : stdout), m_pos(0) {} 39 40 inline substr _get(bool /*error_on_excess*/) 41 { 42 substr sp; 43 sp.str = nullptr; 44 sp.len = m_pos; 45 return sp; 46 } 47 48 template<size_t N> 49 inline void _do_write(const char (&a)[N]) 50 { 51 fwrite(a, sizeof(char), N - 1, m_file); 52 m_pos += N - 1; 53 } 54 55 inline void _do_write(csubstr sp) 56 { 57 #if defined(__clang__) 58 # pragma clang diagnostic push 59 # pragma GCC diagnostic ignored "-Wsign-conversion" 60 #elif defined(__GNUC__) 61 # pragma GCC diagnostic push 62 # pragma GCC diagnostic ignored "-Wsign-conversion" 63 #endif 64 if(sp.empty()) return; 65 fwrite(sp.str, sizeof(csubstr::char_type), sp.len, m_file); 66 m_pos += sp.len; 67 #if defined(__clang__) 68 # pragma clang diagnostic pop 69 #elif defined(__GNUC__) 70 # pragma GCC diagnostic pop 71 #endif 72 } 73 74 inline void _do_write(const char c) 75 { 76 fputc(c, m_file); 77 ++m_pos; 78 } 79 80 inline void _do_write(RepC const rc) 81 { 82 for(size_t i = 0; i < rc.num_times; ++i) 83 { 84 fputc(rc.c, m_file); 85 } 86 m_pos += rc.num_times; 87 } 88 }; 89 90 91 //----------------------------------------------------------------------------- 92 //----------------------------------------------------------------------------- 93 //----------------------------------------------------------------------------- 94 /** A writer that outputs to an STL-like ostream. */ 95 template<class OStream> 96 struct WriterOStream 97 { 98 OStream& m_stream; 99 size_t m_pos; 100 101 WriterOStream(OStream &s) : m_stream(s), m_pos(0) {} 102 103 inline substr _get(bool /*error_on_excess*/) 104 { 105 substr sp; 106 sp.str = nullptr; 107 sp.len = m_pos; 108 return sp; 109 } 110 111 template<size_t N> 112 inline void _do_write(const char (&a)[N]) 113 { 114 m_stream.write(a, N - 1); 115 m_pos += N - 1; 116 } 117 118 inline void _do_write(csubstr sp) 119 { 120 #if defined(__clang__) 121 # pragma clang diagnostic push 122 # pragma GCC diagnostic ignored "-Wsign-conversion" 123 #elif defined(__GNUC__) 124 # pragma GCC diagnostic push 125 # pragma GCC diagnostic ignored "-Wsign-conversion" 126 #endif 127 if(sp.empty()) return; 128 m_stream.write(sp.str, sp.len); 129 m_pos += sp.len; 130 #if defined(__clang__) 131 # pragma clang diagnostic pop 132 #elif defined(__GNUC__) 133 # pragma GCC diagnostic pop 134 #endif 135 } 136 137 inline void _do_write(const char c) 138 { 139 m_stream.put(c); 140 ++m_pos; 141 } 142 143 inline void _do_write(RepC const rc) 144 { 145 for(size_t i = 0; i < rc.num_times; ++i) 146 { 147 m_stream.put(rc.c); 148 } 149 m_pos += rc.num_times; 150 } 151 }; 152 153 154 //----------------------------------------------------------------------------- 155 //----------------------------------------------------------------------------- 156 //----------------------------------------------------------------------------- 157 /** a writer to a substr */ 158 struct WriterBuf 159 { 160 substr m_buf; 161 size_t m_pos; 162 163 WriterBuf(substr sp) : m_buf(sp), m_pos(0) {} 164 165 inline substr _get(bool error_on_excess) 166 { 167 if(m_pos <= m_buf.len) 168 { 169 return m_buf.first(m_pos); 170 } 171 if(error_on_excess) 172 { 173 c4::yml::error("not enough space in the given buffer"); 174 } 175 substr sp; 176 sp.str = nullptr; 177 sp.len = m_pos; 178 return sp; 179 } 180 181 template<size_t N> 182 inline void _do_write(const char (&a)[N]) 183 { 184 RYML_ASSERT( ! m_buf.overlaps(a)); 185 if(m_pos + N-1 <= m_buf.len) 186 { 187 memcpy(&(m_buf[m_pos]), a, N-1); 188 } 189 m_pos += N-1; 190 } 191 192 inline void _do_write(csubstr sp) 193 { 194 if(sp.empty()) return; 195 RYML_ASSERT( ! sp.overlaps(m_buf)); 196 if(m_pos + sp.len <= m_buf.len) 197 { 198 memcpy(&(m_buf[m_pos]), sp.str, sp.len); 199 } 200 m_pos += sp.len; 201 } 202 203 inline void _do_write(const char c) 204 { 205 if(m_pos + 1 <= m_buf.len) 206 { 207 m_buf[m_pos] = c; 208 } 209 ++m_pos; 210 } 211 212 inline void _do_write(RepC const rc) 213 { 214 if(m_pos + rc.num_times <= m_buf.len) 215 { 216 for(size_t i = 0; i < rc.num_times; ++i) 217 { 218 m_buf[m_pos + i] = rc.c; 219 } 220 } 221 m_pos += rc.num_times; 222 } 223 }; 224 225 226 } // namespace yml 227 } // namespace c4 228 229 #endif /* _C4_YML_WRITER_HPP_ */