Sunday, February 13, 2011

Correctly over-loading a stringbuf to replace cout in a MATLAB mex file

MathWorks currently doesn't allow you to use cout from a mex file when the MATLAB desktop is open because they have redirected stdout. Their current workaround is providing a function, mexPrintf, that they request you use instead. After googling around a bit, I think that it's possible to extend the std::stringbuf class to do what I need. Here's what I have so far. Is this robust enough, or are there other methods I need to overload or a better way to do this? (Looking for portability in a general UNIX environment and the ability to use std::cout as normal if this code is not linked against a mex executable)

class mstream : public stringbuf {
public:
  virtual streamsize xsputn(const char *s, std::streamsize n) 
  {
mexPrintf("*s",s,n);
return basic_streambuf<char, std::char_traits<char>>::xsputn(s,n);
  }
}; 

mstream mout;
outbuf = cout.rdbuf(mout.rdbuf());
  • cout is a particular character output stream. If you want a cout that writes to a file, use an fstream, particularly an ofstream. They have the same interface that cout provides. Additionally, if you want to grab their buffer (with rdbuf) you can.

  • You don't really want to overload std::stringbuf, you want to overload std::streambuf or std::basic_streambuf (if you want to support multiple character types), also you need to override the overflow method as well.

    But I also think you need to rethink your solution to your problem.

    cout is just a ostream, so if all classes / functions takes a ostream then you can pass in anything you like. e.g. cout, ofstream, etc

    If that's too hard then I would create my own version of cout, maybe called mycout that can be defined at either compiler time or runtime time (depending on what you want to do).

    A simple solution may be:

    #include <streambuf>
    #include <ostream>
    
    class mystream : public std::streambuf
    {
    public:
        mystream() {}
    
    protected:
        virtual int_type overflow(int_type c)
        {
            if(c != EOF)
            {
                char z = c;
                mexPrintf("%c",c);
                return EOF;
            }
            return c;
        }
    
        virtual std::streamsize xsputn(const char* s, std::streamsize num)
        {
            mexPrintf("*s",s,n);
            return num;
        }
    };
    
    class myostream : public std::ostream
    {
    protected:
        mystream buf;
    
    public:
        myostream() : std::ostream(&buf) {}
    };
    
    myostream mycout;
    

    And the cout version could just be:

    typedef std::cout mycout;
    

    A runtime version is a bit more work but easily doable.

  • Shane, thanks very much for your help. Here's my final working implementation.

    class mstream : public std::streambuf {
    public:
    protected:
      virtual std::streamsize xsputn(const char *s, std::streamsize n); 
      virtual int overflow(int c = EOF);
    };
    

    ...

    std::streamsize 
    mstream::xsputn(const char *s, std::streamsize n) 
    {
      mexPrintf("%.*s",n,s);
      return n;
    }
    
    int 
    mstream::overflow(int c) 
    {
        if (c != EOF) {
          mexPrintf("%.1s",&c);
        }
        return 1;
    }
    

    ...

    mstream mout;
    std::streambuf outbuf = std::cout.rdbuf(&mout);
    

    ...

    std::cout.rdbuf(outbuf);
    
    From

0 comments:

Post a Comment