Parsing “lines”

November 16, 2005
00001: #define BUFFER_SIZE 1<<16
00002: #define ARR_SIZE 1<<16
00003: 
00004: void parse_args(char *buffer, char** args, 
00005:                 size_t args_size, size_t *nargs)
00006: {
00007:     char *buf_args[args_size]; /* You need C99 */
00008:     char **cp;
00009:     char *wbuf;
00010:     size_t i, j;
00011:     
00012:     wbuf=buffer;
00013:     buf_args[0]=buffer; 
00014:     args[0] =buffer;
00015:     
00016:     for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
00017:         if ((*cp != '') && (++cp >= &buf_args[args_size]))
00018:             break;
00019:     }
00020:     
00021:     for (j=i=0; buf_args[i]!=NULL; i++){
00022:         if(strlen(buf_args[i])>0)
00023:             args[j++]=buf_args[i];
00024:     }
00025:     
00026:     *nargs=j;
00027:     args[j]=NULL;
00028: }

To understand how it works, I suggest to take a look at the man page of strsep. As you can see this is a lot of code to perform a very simple task.
Compare with

        argv = cmd.split()

The C++ version is a bit longer (because I split some lines) than the C version, but there is less “magic”. In fact if you read the code it is very easy to understand how it works. Moreovere there is no hassle with memory allocation.

00001: #include <iostream>
00002: #include <string>
00003: #include <vector>
00004: #include <algorithm>
00005: #include <iterator>
00006: #include <cstdlib>
00007: #include <cerrno>
00008: #include <exception>
00009: #include <unistd.h>
00010: 
00011: using std::string;
00012: 
00013: void 
00014: split_string(const std::string s, 
00015:              const std::string sep, 
00016:              std::vector<std::string> &components)
00017: {
00018:     typedef std::pair<size_t, size_t> Range;
00019:     size_t pos, old_pos;
00020:     Range trange;
00021:     std::vector<Range> ranges;
00022:     trange.first = 0;
00023:     trange.second = s.find(sep, trange.first);
00024:     if (trange.second == string::npos){
00025:         trange.second = s.length();
00026:     }        
00027:     ranges.push_back(trange);
00028:     while(trange.second < s.length()){
00029:         trange.first = trange.second + 1;
00030:         trange.second = s.find(sep, trange.first);
00031:         if (trange.second == string::npos){
00032:             trange.second = s.length();
00033:         }
00034:         ranges.push_back(trange);
00035:     }
00036:     
00037:     for (int i = 0; i < ranges.size() ; ++i){
00038:        components.push_back(s.substr(ranges[i].first, 
00039:                 ranges[i].second - ranges[i].first) );
00040:     }
00041: }
00042: 
00043: class InvalidCommandLine : public std::exception {
00044: 
00045: };

A simple “counter” example, C, C++, Python

November 3, 2005

Counter is a very simple class. In fact it is meant to be used “as a function”. In C you would have used a static variable, for example:

counter.c (download)
int counter(){
    static int n  = -1;
    ++n;
    return n;
}

Although the C version is shorter, the Python (or C++) solution is cleaner. In fact counter() is a function, but it also contains data. From a logical point of view, it should be a class. In fact in C++ it would have been:

counter.cc (download)
class Counter{
    int n_;
public:
    Counter() : n_(0) {}
    Counter(int i) : n_(i) {}
    int operator()(){
        return n_++;
    }
};

Notice that the Python version permits to define a custom function to set the step of the counter. Of course this could have been done also in C or in C++, but the result would have been a bit longer.
After the class definition, we show a typical use of the counter.

counter.py (download)
class Counter(object):
    def __init__(self, fvalue=0, inc = lambda x: x + 1):
        self.inc = inc
        self.val = fvalue
    def __call__(self):
        old = self.val
        self.val = self.inc(self.val)
        return old
        
        
c = Counter(1)
print [ c() for i in xrange(0, 10)]