using libfmt to format to a string - c++

using libfmt to print to a file is very convenient:
auto file = fmt::output_file(filename);
file.print(...);
But how can I format to a memory buffer, ultimatiley converting to a string? I would imagine something like
auto buf = some_buffer_object{};
buf.print(...);
std::string s = buf.get_string();
But I can find no such buffer type in the documentation (fmt::memory_buffer seems related, but does not work like this).
Important: I need multiple calls to print, so auto s = fmt::format(...) is not an option.

how can I format to a memory buffer, ultimatiley converting to a string?
Use format_to and print to an iterator the appends to a string.

Related

How to deserialize a std::string to a concrete message in Cap'n Proto C++?

I need to decode a message from a std::string object.
I can see how to do this in Java by using a ByteBuffer, but I failed to find a simple C++ equivalent.
More precisely, how to implement this?
const std::string serialized_data = ...; // Source
SomeDataType data = ???; // How to convert from serialized_data to data?
You can write code like this:
std::string serialized_data = ...;
kj::ArrayPtr<const capnp::word> words(
reinterpret_cast<const capnp::word*>(serialized_data.begin()),
serialized_data.size() / sizeof(capnp::word));
capnp::FlatAraryMessageReader reader(words);
Note that this assumes that the backing buffer of an std::string is always word-aligned. I think this is true, but I am not sure. If it is not aligned, you will get exceptions saying so. In this case it may be necessary to copy the data into an aligned buffer:
auto words = kj::heapArray<capnp::word>(
serialized_data.size() / sizeof(capnp::word));
memcpy(words.begin(), serialized_data.begin(), words.asBytes().size());
capnp::FlatAraryMessageReader reader(words);
Note that while std::string is technically able to store arbitrary bytes, it is not a particularly good data structure for this purpose, since it is optimized for text. For example, it may re-allocate and copy your buffer in order to add a NUL terminator to support .c_str(). I would recommend using a more data-oriented type for byte arrays.
My own answer is very similar to Kenton's:
std::string serialized_data = ...;
kj::ArrayPtr<const kj::byte> arr(
reinterpret_cast<const kj::byte*>(serialized_data.data()),
serialized_data.size());
kj::ArrayInputStream stream(arr);
capnp::InputStreamMessageReader reader(stream);
auto data = reader.getRoot<SomeDataType>();
This is isomorphic to the Java version, and it has no alignment requirements.
But Kenton's solution is more straightforward than this. Therefore I will simplify my program further.

Using sprintf with std::string in C++

I am using sprintf function in C++ 11, in the following way:
std::string toString()
{
std::string output;
uint32_t strSize=512;
do
{
output.reserve(strSize);
int ret = sprintf(output.c_str(), "Type=%u Version=%u ContentType=%u contentFormatVersion=%u magic=%04x Seg=%u",
INDEX_RECORD_TYPE_SERIALIZATION_HEADER,
FORAMT_VERSION,
contentType,
contentFormatVersion,
magic,
segmentId);
strSize *= 2;
} while (ret < 0);
return output;
}
Is there a better way to do this, than to check every time if the reserved space was enough? For future possibility of adding more things.
Your construct -- writing into the buffer received from c_str() -- is undefined behaviour, even if you checked the string's capacity beforehand. (The return value is a pointer to const char, and the function itself marked const, for a reason.)
Don't mix C and C++, especially not for writing into internal object representation. (That is breaking very basic OOP.) Use C++, for type safety and not running into conversion specifier / parameter mismatches, if for nothing else.
std::ostringstream s;
s << "Type=" << INDEX_RECORD_TYPE_SERIALIZATION_HEADER
<< " Version=" << FORMAT_VERSION
// ...and so on...
;
std::string output = s.str();
Alternative:
std::string output = "Type=" + std::to_string( INDEX_RECORD_TYPE_SERIALIZATION_HEADER )
+ " Version=" + std::to_string( FORMAT_VERSION )
// ...and so on...
;
The C++ patterns shown in other answers are nicer, but for completeness, here is a correct way with sprintf:
auto format = "your %x format %d string %s";
auto size = std::snprintf(nullptr, 0, format /* Arguments go here*/);
std::string output(size + 1, '\0');
std::sprintf(&output[0], format, /* Arguments go here*/);
Pay attention to
You must resize your string. reserve does not change the size of the buffer. In my example, I construct correctly sized string directly.
c_str() returns a const char*. You may not pass it to sprintf.
std::string buffer was not guaranteed to be contiguous prior to C++11 and this relies on that guarantee. If you need to support exotic pre-C++11 conforming platforms that use rope implementation for std::string, then you're probably better off sprinting into std::vector<char> first and then copying the vector to the string.
This only works if the arguments are not modified between the size calculation and formatting; use either local copies of variables or thread synchronisation primitives for multi-threaded code.
We can mix code from here https://stackoverflow.com/a/36909699/2667451 and here https://stackoverflow.com/a/7257307 and result will be like that:
template <typename ...Args>
std::string stringWithFormat(const std::string& format, Args && ...args)
{
auto size = std::snprintf(nullptr, 0, format.c_str(), std::forward<Args>(args)...);
std::string output(size + 1, '\0');
std::sprintf(&output[0], format.c_str(), std::forward<Args>(args)...);
return output;
}
A better way is to use the {fmt} library. Ex:
std::string message = fmt::sprintf("The answer is %d", 42);
It exposes also a nicer interface than iostreams and printf. Ex:
std::string message = fmt::format("The answer is {}", 42);`
See:
https://github.com/fmtlib/fmt
http://fmtlib.net/latest/api.html#printf-formatting-functions
Your code is wrong. reserve allocates memory for the string, but does not change its size. Writing into the buffer returned by c_str does not change its size either. So the string still believes its size is 0, and you've just written something into the unused space in the string's buffer. (Probably. Technically, the code has Undefined Behaviour, because writing into c_str is undefined, so anything could happen).
What you really want to do is forget sprintf and similar C-style functions, and use the C++ way of string formatting—string streams:
std::ostringstream ss;
ss << "Type=" << INDEX_RECORD_TYPE_SERIALIZATION_HEADER
<< " Version=" << FORAMT_VERSION
<< /* ... the rest ... */;
return ss.str();
Yes, there is!
In C, the better way is to associate a file with the null device and make a dummy printf of the desired output to it, to learn how much space would it take if actually printed. Then allocate appropriate buffer and sprintf the same data to it.
In C++ you could associate the output stream with a null device, too, and test the number of charactes printed with std::ostream::tellp. However, using ostringstream is a way better solution – see the answers by DevSolar or Angew.
You can use an implementation of sprintf() into a std::string I wrote that uses vsnprintf() under the hood.
It splits the format string into sections of plain text which are just copied to the destination std::string and sections of format fields (such as %5.2lf) which are first vsnprintf()ed into a buffer and then appended to the destination.
https://gitlab.com/eltomito/bodacious-sprintf

How to append to a string without changing original value when passing as a parameter?

I am making a PONG clone in C++/SDL, and I have all of my images in the directory in which the program starts. I am successfully able to find that path using GetCurrentDirectory() and open the file using strcat() to append the actual image and it will load fine, but this will change the original value, which makes it useless when I try to load the next image. How would I pass the path without changing the original value, or another way to work around this problem.
My current code:
TCHAR openingdirectorytemp [MAX_PATH];
bgtexturesurf = SDL_LoadBMP(strcat(openingdirectorytemp, "\\bg.bmp"));
Use actual C++ strings:
#include <string>
using std::string;
void child(const string str)
{
str += ".suffix"; // parameter str is a copy of argument
}
void parent()
{
string parents_string = "abc";
child(parents_string);
// parents_string is not modified
}
If you must work with TCHAR in the Windows API world, use std::basic_string<TCHAR>:
typedef std::basic_string<TCHAR> str_t; // now use str_t everywhere
and so the code becomes something like
void my_class::load_bg_bmp(const str_t &dir_path)
{
str_t file_path = dir_path + _T("\\bg.bmp")l
bgtexturesurf = SDL_LoadBMP(file_path.c_str()));
// ...
}
The TCHAR type allows for build times switching between narrow and wide characters. It is pointless to use TCHAR, but then use unwrapped narrow character string literals like "\\bg.tmp".
Also, note that strcat to an uninitialized array invokes undefined behavior. The first argument to strcat must be a string: a pointer to the first-element of a null terminated character array. An uninitialized array is not a string.
We can avoid such low-level nasties by using the C++ string class.
Although you can use C++ string as suggested by other answers, you can still keep your C approach.
What you need to do is just to create another string by copying the contents from the original, and use it for strcat:
TCHAR openingdirectorytemp [MAX_PATH];
TCHAR path [MAX_PATH];
strcpy(path, openingdirectorytemp);
bgtexturesurf = SDL_LoadBMP(strcat(path, "\\bg.bmp"));
By doing so, you create string path with a separate memory space, so strcat won't affect openingdirectorytemp
You need to make a copy of the string before concatenating if you are worried about things getting changed. In other words
string1 = "abc"
string2 = "def"
strcat(string1, string2);
Results in
string1 = "abcdef"
since that is what you asked the program to do. Instead, add
strcpy(string3, string1)
strcat(string3, string2);
Now you will have
string1 = "abc"
string3 = "abcdef"
Of course you need to make sure enough space is allocated, etc.
Once you are using c++, you can use string to compose your final pathname:
string pathname(path);
pathname += "\\bg.bmp";
bgtexturesurf = SDL_LoadBMP(pathname.c_str());

Print text between pointers

I have a character range with pointers (pBegin and pEnd). I think of it as a string, but it is not \0 terminated. How can I print it to std::cout effectively?
Without creating a copy, like with std::string
Without a loop that prints each character
Do we have good solution? If not, what is the smoothest workaround?
You can use ostream::write, which takes pointer and length arguments:
std::cout.write(pBegin, pEnd - pBegin);
Since C++17 you can use std::string_view, which was created for sharing part of std::string without copying
std::cout << std::string_view(pBegin, pEnd - pBegin);
pEnd must point to one pass the last character to print, like how iterators in C++ work, instead of the last character to print
What is string_view?
In C++11 what is the most performant way to return a reference/pointer to a position in a std::string?
In older C++ standards boost::string_ref is an alternative. Newer boost versions also have boost::string_view with the same semantics as std::string_view. See Differences between boost::string_ref and boost::string_view
If you use Qt then there's also QStringView and QStringRef although unfortunately they're used for viewing QString which stores data in UTF-16 instead of UTF-8 or a byte-oriented encoding
However if you need to process the string by some functions that require null-terminated string without any external libraries then there's a simple solution
char tmpEnd = *pEnd; // backup the after-end character
*pEnd = '\0';
std::cout << pBegin; // use it as normal C-style string, like dosomething(pBegin);
*pEnd = tmpEnd; // restore the char
In this case make sure that pEnd still points to an element inside the original array and not one past the end of it

How to convert AS3 ByteArray into wchar_t const* filename? (Adobe Alchemy)

How to convert AS3 ByteArray into wchar_t const* filename?
So in my C code I have a function waiting for a file with void fun (wchar_t const* filename) how to send to that function my ByteArray? (Or, how should I re-write my function?)
A four month old question. Better late than never?
To convert a ByteArray to a String in AS3, there are two ways depending on how the String was stored. Firstly, if you use writeUTF it will write an unsigned short representing the String's length first, then write out the string data. The string is easiest to recover this way. Here's how it's done in AS3:
byteArray.position = 0;
var str:String = byteArray.readUTF();
Alternatively, toString also works in this case. The second way to store is with writeUTFBytes. This won't write the length to the beginning, so you'll need to track it independantly somehow. It sounds like you want the entire ByteArray to be a single String, so you can use the ByteArray's length.
byteArray.position = 0;
var str:String = byteArray.readUTFBytes(byteArray.length);
Since you want to do this with Alchemy, you just need to convert the above code. Here's a conversion of the second example:
std::string batostr(AS3_Val byteArray) {
AS3_SetS(byteArray, "position", AS3_Int(0));
return AS3_StringValue(AS3_CallS("readUTFBytes", byteArray,
AS3_Array("AS3ValType", AS3_GetS(byteArray, "length")) ));
}
This has a ridiculous amount of memory leaks, of course, since I'm not calling AS3_Release anywhere. I use a RAII wrapper for AS3_Val in my own code... for the sake of my sanity. As should you.
Anyway, the std::string my function returns will be UTF-8 multibyte. Any standard C++ technique for converting to wide characters should work from here. (search the site for endless reposts) I suggest leaving it is as it, though. I can't think of any advantage to using wide characters on this platform.