Skip to content

Add support for fixed sized buffers #105

Closed

Description

@mateofio

This library looks very promising. One thing that's missing is efficient snprintf() like functionality which can print directly to a fixed size buffer with truncation but without any memory allocations.

I would suggest an interface like this:

StringRef format(ArrayRef<char> buffer, StringRef fmt, ArgList args);

In this example, ArrayRef would be a simplified version of array_view which is proposed for C++17. You don't need all of the multi-dimensional and striding support, just a generic adapter for any array type container.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3851.pdf

The returned StringRef references a sub-array of buffer that was filled in by the formatting.

Usage example:

char path_buf[4096];
auto path = format(path_buf, "{}/{}", dir, filename);

Activity

  1. vitaut commented on Feb 9, 2015

    @vitaut
    Contributor

    Thank you for the suggestion. The library already doesn't do dynamic memory allocations if the result of formatting is less than fmt::internal::INLINE_BUFFER_SIZE (which you can configure to better suit your application):

    fmt::MemoryWriter w;
    w.write("{}/{}", dir, filename); // no dynamic memory allocation for small output
    w.c_str(); // returns a pointer to the internal buffer

    The advantage of this method is that it works with large output by using dynamic memory allocation (only) if necessary.

    Also you can define your own function (or a writer class) that prints directly to a fixed buffer:

    #include "format.h"
    
    class FixedBuffer : public fmt::internal::Buffer<char> {
     public:
      FixedBuffer(char *array, std::size_t size)
        : fmt::internal::Buffer<char>(array, size) {}
    
     protected:
      void grow(std::size_t size) {
        throw std::runtime_error("buffer overflow");
      }
    };
    
    class FixedWriter : public fmt::Writer {
     private:
      FixedBuffer buffer_;
     public:
      FixedWriter(char *array, std::size_t size)
        : fmt::Writer(buffer_), buffer_(array, size) {}
    };
    
    int main() {
      char buffer[100];
      FixedWriter w(buffer, sizeof(buffer));
      w.write("Hello, {}!", "world");
    }
  2. vitaut commented on Feb 10, 2015

    @vitaut
    Contributor

    Closing for now, but feel free to reopen if the alternatives I described don't fit your use cases.

  3. patlecat commented on Feb 17, 2015

    @patlecat

    @vitaut So fmt::internal::INLINE_BUFFER_SIZE should and can only be configured by deriving my own class like in your example above? Otherwise how is it defined?

  4. vitaut commented on Feb 17, 2015

    @vitaut
    Contributor

    @patlecat No, you can change the value of fmt::internal::INLINE_BUFFER_SIZE constant if you embed C++ Format in your application (although in most cases the default should be fine). Deriving your own class is only necessary if you want to support a custom buffer, e.g. fixed-sized as in the above example.

  5. vitaut commented on Mar 2, 2015

    @vitaut
    Contributor

    C++ Format now supports formatting to fixed-size arrays: http://cppformat.readthedocs.org/en/latest/reference.html#fmt::BasicArrayWriter.

    Example:

    char buffer[100];
    fmt::ArrayWriter w(buffer);
    w.write("The answer is {}", 42);
    
  6. patlecat commented on Mar 2, 2015

    @patlecat

    Does this represent any performance gain in any way or is it just a convenience for C code?

  7. vitaut commented on Mar 2, 2015

    @vitaut
    Contributor

    There is no performance gain. It's mostly for the case where you can't replace the destination array with MemoryWriter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions