Browse Source

Multiple performance optimizations

master
Artyom Beilis 13 years ago
parent
commit
2eff10483e
9 changed files with 859 additions and 84 deletions
  1. +89
    -1
      cppcms/json.h
  2. +117
    -0
      cppcms/steal_buf.h
  3. +330
    -0
      cppcms/string_key.h
  4. +63
    -2
      cppcms/url_mapper.h
  5. +16
    -0
      cppcms/util.h
  6. +9
    -2
      src/filters.cpp
  7. +29
    -9
      src/json.cpp
  8. +168
    -59
      src/url_mapper.cpp
  9. +38
    -11
      src/util.cpp

+ 89
- 1
cppcms/json.h View File

@@ -20,6 +20,7 @@
#define CPPCMS_JSON_H

#include <cppcms/defs.h>
#include <cppcms/string_key.h>
#include <booster/copy_ptr.h>
#include <booster/backtrace.h>
#include <vector>
@@ -60,7 +61,7 @@ namespace json {
///
/// The json::object - std::map of json::value's
///
typedef std::map<std::string,value> object;
typedef std::map<string_key,value> object;

#ifdef CPPCMS_DOXYGEN_DOCS

@@ -263,6 +264,14 @@ namespace json {
/// that holds an object { "y" : 10 } and find("foo") would return value of undefined type.
///
value const &find(std::string const &path) const;
///
/// Searches a value in the path \a path
///
/// For example if the json::value represents { "x" : { "y" : 10 } }, then find("x.y") would return
/// a reference to value that hold a number 10, find("x") returns a reference to a value
/// that holds an object { "y" : 10 } and find("foo") would return value of undefined type.
///
value const &find(char const *path) const;

///
/// Searches a value in the path \a path, if not found throw bad_value_cast.
@@ -279,12 +288,32 @@ namespace json {
/// a reference to value that hold a number 10, find("x") returns a reference to a value
/// that holds an object { "y" : 10 } and find("foo") throws
///
value const &at(char const *path) const;
///
/// Searches a value in the path \a path, if not found throw bad_value_cast.
///
/// For example if the json::value represents { "x" : { "y" : 10 } }, then find("x.y") would return
/// a reference to value that hold a number 10, find("x") returns a reference to a value
/// that holds an object { "y" : 10 } and find("foo") throws
///
value &at(std::string const &path);
///
/// Searches a value in the path \a path, if not found throw bad_value_cast.
///
/// For example if the json::value represents { "x" : { "y" : 10 } }, then find("x.y") would return
/// a reference to value that hold a number 10, find("x") returns a reference to a value
/// that holds an object { "y" : 10 } and find("foo") throws
///
value &at(char const *path);

///
/// Sets the value \a v at the path \a path, if the path invalid, creates it.
///
void at(std::string const &path,value const &v);
///
/// Sets the value \a v at the path \a path, if the path invalid, creates it.
///
void at(char const *path,value const &v);

///
@@ -305,6 +334,15 @@ namespace json {
{
return find(path).type();
}
///
/// Returns the type of variable in path, if not found returns undefined
///
/// Same as find(path).type()
///
json_type type(char const *path) const
{
return find(path).type();
}

///
/// Convert an object \a v of type T to a value at specific path, same as at(path,value(v))
@@ -314,6 +352,14 @@ namespace json {
{
at(path,value(v));
}
///
/// Convert an object \a v of type T to a value at specific path, same as at(path,value(v))
///
template<typename T>
void set(char const *path,T const &v)
{
at(path,value(v));
}

///
/// Get a string value from a path \a path. If the path is not invalid or the object
@@ -331,6 +377,22 @@ namespace json {
return def;
}
}
///
/// Get a string value from a path \a path. If the path is not invalid or the object
/// is not of type string at this path, returns \a def instead
///
std::string get(char const *path,char const *def) const
{
value const &v=find(path);
if(v.is_undefined())
return def;
try {
return v.get_value<std::string>();
}
catch(std::bad_cast const &e) {
return def;
}
}
///
/// Get an object of type T from the path \a path. Throws bad_value_cast if such path does not
@@ -341,12 +403,38 @@ namespace json {
{
return at(path).get_value<T>();
}
///
/// Get an object of type T from the path \a path. Throws bad_value_cast if such path does not
/// exists of conversion can't be done
///
template<typename T>
T get(char const *path) const
{
return at(path).get_value<T>();
}

///
/// Get an object of type T from the path \a path. Returns \a def if such path does not
/// exists of conversion can't be done
///
template<typename T>
T get(char const *path,T const &def) const
{
value const &v=find(path);
if(v.is_undefined())
return def;
try {
return v.get_value<T>();
}
catch(std::bad_cast const &e) {
return def;
}
}
///
/// Get an object of type T from the path \a path. Returns \a def if such path does not
/// exists of conversion can't be done
///
template<typename T>
T get(std::string const &path,T const &def) const
{
value const &v=find(path);


+ 117
- 0
cppcms/steal_buf.h View File

@@ -0,0 +1,117 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_STEAL_BUF_H
#define CPPCMS_STEAL_BUF_H

#include <streambuf>
#include <ostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <stdlib.h>

namespace cppcms {
namespace util {

template<size_t on_stack_size = 128>
class steal_buffer : public std::streambuf {
steal_buffer(steal_buffer const &);
void operator=(steal_buffer const &);
public:
char *begin()
{
return pbase();
}
char *end()
{
return pptr();
}
steal_buffer(std::ostream &out)
{
init();
steal(out);
}
steal_buffer()
{
init();
}
void steal(std::ostream &out)
{
release();
stolen_ = out.rdbuf(this);
stream_ = &out;
}
void release()
{
if(stream_ && stolen_) {
stream_->rdbuf(stolen_);
}
stream_ = 0;
stolen_ = 0;
}
~steal_buffer()
{
release();
free(on_heap_);
}
int overflow(int c)
{
size_t current_size;
size_t new_size;
if(pbase() == on_stack_) {
current_size = on_stack_size;
new_size = on_stack_size * 2;
on_heap_ = (char *)malloc(new_size);
if(!on_heap_)
throw std::bad_alloc();
memcpy(on_heap_,on_stack_,current_size);
}
else {
current_size = pptr() - pbase();
new_size = current_size * 2;
char *new_ptr = (char *)realloc(on_heap_,new_size);
if(!new_ptr)
throw std::bad_alloc();
on_heap_ = new_ptr;

}
setp(on_heap_,on_heap_ + new_size);
pbump(current_size);
if(c!=EOF)
sputc(c);
return 0;
}
private:
void init()
{
on_heap_ = 0;
stolen_ = 0;
stream_ = 0;
setp(on_stack_,on_stack_+on_stack_size);
}
char *on_heap_;
std::streambuf *stolen_;
std::ostream *stream_;
char on_stack_[on_stack_size];
};
} // util
} // cppcms

#endif

+ 330
- 0
cppcms/string_key.h View File

@@ -0,0 +1,330 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_STRING_KEY_H
#define CPPCMS_STRING_KEY_H

#include <string>
#include <string.h>
#include <algorithm>
#include <stdexcept>
#include <ostream>

namespace cppcms {
class string_key {
public:

typedef char const *const_iterator;

static const size_t npos = std::string::npos;
string_key() :
begin_(0),
end_(0)
{
}

string_key(char const *key) :
begin_(0),
end_(0),
key_(key)
{
}
string_key(std::string const &key) :
begin_(0),
end_(0),
key_(key)
{
}

size_t size() const
{
return end() - begin();
}
size_t length() const
{
return size();
}
void clear()
{
begin_ = end_ = 0;
key_.clear();
}
bool empty() const
{
return end() == begin();
}

size_t find(char c,size_t pos = 0) const
{
size_t s = size();
if(pos >= s)
return npos;
char const *p=begin() + pos;
while(pos <= s && *p!=c) {
pos++;
p++;
}
if(pos >= s)
return npos;
return pos;
}

string_key substr(size_t pos = 0,size_t n=npos) const
{
string_key tmp = unowned_substr(pos,n);
return string_key(std::string(tmp.begin(),tmp.end()));
}
string_key unowned_substr(size_t pos = 0,size_t n=npos) const
{
if(pos >= size()) {
return string_key();
}
char const *p=begin() + pos;
char const *e=end();
if(n > size_t(e-p)) {
return string_key(p,e);
}
else {
return string_key(p,p+n);
}
}

char const &operator[](size_t n) const
{
return *(begin() + n);
}
char const &at(size_t n) const
{
if(n > size())
throw std::out_of_range("cppcms::string_key::at() range error");
return *(begin() + n);
}

static string_key unowned(std::string const &v)
{
return string_key(v.c_str(),v.c_str()+v.size());
}
static string_key unowned(char const *str)
{
char const *end = str;
while(*end)
end++;
return string_key(str,end);
}
static string_key unowned(char const *begin,char const *end)
{
return string_key(begin,end);
}

char const *begin() const
{
if(begin_)
return begin_;
return key_.c_str();
}
char const *end() const
{
if(begin_)
return end_;
return key_.c_str() + key_.size();
}
bool operator<(string_key const &other) const
{
return std::lexicographical_compare( begin(),end(),
other.begin(),other.end(),
std::char_traits<char>::lt);
}
bool operator>(string_key const &other) const
{
return other < *this;
}
bool operator>=(string_key const &other) const
{
return !(*this < other);
}
bool operator<=(string_key const &other) const
{
return !(*this > other);
}
bool operator==(string_key const &other) const
{
return (end() - begin() == other.end() - other.begin())
&& memcmp(begin(),other.begin(),end()-begin()) == 0;
}
bool operator!=(string_key const &other) const
{
return !(*this!=other);
}

char const *data() const
{
return begin();
}

std::string str() const
{
if(begin_)
return std::string(begin_,end_-begin_);
else
return key_;
}
operator std::string() const
{
return str();
}
private:
string_key(char const *b,char const *e) :
begin_(b),
end_(e)
{
}

char const *begin_;
char const *end_;
std::string key_;
};

inline std::ostream &operator<<(std::ostream &out,string_key const &s)
{
out.write(s.data(),s.size());
return out;
}

inline bool operator==(string_key const &l,char const *r)
{
return l==string_key::unowned(r);
}

inline bool operator==(char const *l,string_key const &r)
{
return string_key::unowned(l) == r;
}

inline bool operator==(string_key const &l,std::string const &r)
{
return l==string_key::unowned(r);
}

inline bool operator==(std::string const &l,string_key const &r)
{
return string_key::unowned(l) == r;
}

inline bool operator!=(string_key const &l,char const *r)
{
return l!=string_key::unowned(r);
}

inline bool operator!=(char const *l,string_key const &r)
{
return string_key::unowned(l) != r;
}

inline bool operator!=(string_key const &l,std::string const &r)
{
return l!=string_key::unowned(r);
}

inline bool operator!=(std::string const &l,string_key const &r)
{
return string_key::unowned(l) != r;
}
inline bool operator<=(string_key const &l,char const *r)
{
return l<=string_key::unowned(r);
}

inline bool operator<=(char const *l,string_key const &r)
{
return string_key::unowned(l) <= r;
}

inline bool operator<=(string_key const &l,std::string const &r)
{
return l<=string_key::unowned(r);
}

inline bool operator<=(std::string const &l,string_key const &r)
{
return string_key::unowned(l) <= r;
}
inline bool operator>=(string_key const &l,char const *r)
{
return l>=string_key::unowned(r);
}

inline bool operator>=(char const *l,string_key const &r)
{
return string_key::unowned(l) >= r;
}

inline bool operator>=(string_key const &l,std::string const &r)
{
return l>=string_key::unowned(r);
}

inline bool operator>=(std::string const &l,string_key const &r)
{
return string_key::unowned(l) >= r;
}


inline bool operator<(string_key const &l,char const *r)
{
return l<string_key::unowned(r);
}

inline bool operator<(char const *l,string_key const &r)
{
return string_key::unowned(l) < r;
}

inline bool operator<(string_key const &l,std::string const &r)
{
return l<string_key::unowned(r);
}

inline bool operator<(std::string const &l,string_key const &r)
{
return string_key::unowned(l) < r;
}
inline bool operator>(string_key const &l,char const *r)
{
return l>string_key::unowned(r);
}

inline bool operator>(char const *l,string_key const &r)
{
return string_key::unowned(l) > r;
}

inline bool operator>(string_key const &l,std::string const &r)
{
return l>string_key::unowned(r);
}

inline bool operator>(std::string const &l,string_key const &r)
{
return string_key::unowned(l) > r;
}

}

#endif

+ 63
- 2
cppcms/url_mapper.h View File

@@ -20,6 +20,7 @@
#define CPPCMS_URL_MAPPER_H

#include <cppcms/defs.h>
#include <cppcms/string_key.h>
#include <booster/noncopyable.h>
#include <booster/hold_ptr.h>
#include <cppcms/filters.h>
@@ -233,6 +234,66 @@ namespace cppcms {
/// Write the URL to output stream \a out for the URL \a path with 0 parameters
///
void map( std::ostream &out,
char const *path);

///
/// Write the URL to output stream \a out for the URL \a path with 1 parameters
///
void map( std::ostream &out,
char const *path,
filters::streamable const &p1);

///
/// Write the URL to output stream \a out for the URL \a path with 2 parameters
///
void map( std::ostream &out,
char const *path,
filters::streamable const &p1,
filters::streamable const &p2);

///
/// Write the URL to output stream \a out for the URL \a path with 3 parameters
///
void map( std::ostream &out,
char const *path,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3);

///
/// Write the URL to output stream \a out for the URL \a path with 4 parameters
///
void map( std::ostream &out,
char const *path,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
filters::streamable const &p4);
///
/// Write the URL to output stream \a out for the URL \a path with 5 parameters
///
void map( std::ostream &out,
char const *path,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
filters::streamable const &p4,
filters::streamable const &p5);
///
/// Write the URL to output stream \a out for the URL \a path with 6 parameters
///
void map( std::ostream &out,
char const *path,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
filters::streamable const &p4,
filters::streamable const &p5,
filters::streamable const &p6);
///
/// Write the URL to output stream \a out for the URL \a path with 0 parameters
///
void map( std::ostream &out,
std::string const &path);

///
@@ -314,9 +375,9 @@ namespace cppcms {

private:
void real_assign(std::string const &key,std::string const &url,application *child = 0);
url_mapper &get_mapper_for_key(std::string const &key,std::string &real_key,std::vector<std::string> &direct);
url_mapper &get_mapper_for_key(string_key const &key,string_key &real_key,std::vector<string_key> &direct);
url_mapper *root_mapper();
void real_map( std::string const &key,
void real_map( char const *key,
filters::streamable const *const *params,
size_t params_no,
std::ostream &output);


+ 16
- 0
cppcms/util.h View File

@@ -42,10 +42,26 @@ namespace cppcms {
///
std::string CPPCMS_API escape(std::string const &s);
///
/// Escape string for inclusion in HTML page, i.e.
///
/// - < - \&lt;
/// - > - \&gt;
/// - \& - \&amp;
/// - &quot; - \&quot;
///
/// Note, this function does not deal with encodings, so it's up to you to
/// provide valid text encoding
///
void CPPCMS_API escape(char const *begin,char const *end,std::ostream &output);
///
/// Encode string for URL (percent encoding)
///
std::string CPPCMS_API urlencode(std::string const &s);
///
/// Encode string for URL (percent encoding)
///
void CPPCMS_API urlencode(char const *begin,char const *end,std::ostream &output);
///
/// Decode string from URL-encoding (percent-encoding)
///
std::string CPPCMS_API urldecode(std::string const &s);


+ 9
- 2
src/filters.cpp View File

@@ -18,6 +18,7 @@
///////////////////////////////////////////////////////////////////////////////
#define CPPCMS_SOURCE
#include <cppcms/filters.h>
#include <cppcms/steal_buf.h>
#include <cppcms/base64.h>
#include <cppcms/util.h>
#include <iostream>
@@ -135,7 +136,10 @@ namespace cppcms { namespace filters {
escape const &escape::operator=(escape const &other){ obj_ = other.obj_; return *this; }
void escape::operator()(std::ostream &out) const
{
out << util::escape(obj_.get(out));
util::steal_buffer<> sb(out);
obj_(out);
sb.release();
util::escape(sb.begin(),sb.end(),out);
}

struct urlencode::_data {};
@@ -146,7 +150,10 @@ namespace cppcms { namespace filters {
urlencode const &urlencode::operator=(urlencode const &other){ obj_ = other.obj_; return *this; }
void urlencode::operator()(std::ostream &out) const
{
out << util::urlencode(obj_.get(out));
util::steal_buffer<> sb(out);
obj_(out);
sb.release();
util::urlencode(sb.begin(),sb.end(),out);
}

struct raw::_data {};


+ 29
- 9
src/json.cpp View File

@@ -402,15 +402,16 @@ namespace json {


// returns empty if not found
value const &value::find(std::string const &path) const
value const &value::find(char const *cpath) const
{
string_key path=string_key::unowned(cpath);
static value const empty;
value const *ptr=this;
size_t pos=0;
size_t new_pos;
do {
new_pos=path.find('.',pos);
std::string const part=path.substr(pos,new_pos - pos);
string_key const part=path.unowned_substr(pos,new_pos - pos);
if(new_pos!=std::string::npos)
new_pos++;
if(part.empty())
@@ -427,23 +428,37 @@ namespace json {
} while(new_pos < path.size());
return *ptr;
}
// returns empty if not found
value const &value::find(std::string const &path) const
{
return find(path.c_str());
}
// throws if not found
value const &value::at(std::string const &path) const
{
return at(path.c_str());
}
value const &value::at(char const *path) const
{
value const &v=find(path);
if(v.is_undefined())
throw bad_value_cast("Value not found at "+path );
throw bad_value_cast(std::string("Value not found at ")+path );
return v;
}
value &value::at(std::string const &path)
{
return at(path.c_str());
}
value &value::at(char const *cpath)
{
string_key path=string_key::unowned(cpath);
value *ptr=this;
size_t pos=0;
size_t new_pos;
do {
new_pos=path.find('.',pos);
std::string part=path.substr(pos,new_pos - pos);
string_key part=path.unowned_substr(pos,new_pos - pos);
if(new_pos!=std::string::npos)
new_pos++;
if(part.empty())
@@ -453,7 +468,7 @@ namespace json {
json::object &obj=ptr->object();
json::object::iterator p;
if((p=obj.find(part))==obj.end())
throw bad_value_cast("Member "+part+" not found");
throw bad_value_cast("Member "+part.str()+" not found");
ptr=&p->second;
pos=new_pos;

@@ -462,12 +477,17 @@ namespace json {
}
void value::at(std::string const &path,value const &v)
{
at(path.c_str(),v);
}
void value::at(char const *cpath,value const &v)
{
string_key path=string_key::unowned(cpath);
value *ptr=this;
size_t pos=0;
size_t new_pos;
do {
new_pos=path.find('.',pos);
std::string part=path.substr(pos,new_pos - pos);
string_key part=path.unowned_substr(pos,new_pos - pos);


if(new_pos!=std::string::npos)
@@ -480,7 +500,7 @@ namespace json {
json::object &obj=ptr->object();
json::object::iterator p;
if((p=obj.find(part))==obj.end()) {
ptr=&obj.insert(std::make_pair(part,json::value())).first->second;
ptr=&obj.insert(std::make_pair(part.str(),json::value())).first->second;
}
else
ptr=&p->second;
@@ -497,7 +517,7 @@ namespace json {

json::object &self=object();

json::object::iterator p=self.find(name);
json::object::iterator p=self.find(string_key::unowned(name));
if(p==self.end())
return self.insert(std::make_pair(name,value())).first->second;
return p->second;
@@ -508,7 +528,7 @@ namespace json {
if(type()!=json::is_object)
throw bad_value_cast("",type(),json::is_object);
json::object const &self=object();
json::object::const_iterator p=self.find(name);
json::object::const_iterator p=self.find(string_key::unowned(name));
if(p==self.end())
throw bad_value_cast("Member "+name+" not found");
return p->second;


+ 168
- 59
src/url_mapper.cpp View File

@@ -27,8 +27,32 @@
#include <iostream>

namespace cppcms {

template<typename Data,typename Entry>
struct stream_it {
Data const *self;
Entry const &formatting;
filters::streamable const * const *params;
size_t params_no;
std::map<string_key,std::string> const &data_helpers_default;
std::map<string_key,std::string> const &data_helpers_override;
void write(std::ostream &out) const
{
self->write(formatting,params,params_no,data_helpers_default,data_helpers_override,out);
}
};

template<typename Data,typename Entry>
std::ostream &operator<<(std::ostream &out,stream_it<Data,Entry> const &wr)
{
wr.write(out);
return out;
}


struct url_mapper::data
{

data() : parent(0),this_application(0) {}
std::string this_name;
application *parent;
@@ -41,29 +65,32 @@ namespace cppcms {
application *child;
entry() : child(0) {}
};
template<typename Data,typename Entry>
friend struct stream_it;

typedef std::map<size_t,entry> by_size_type;
typedef std::map<std::string,by_size_type> by_key_type;
typedef std::map<std::string,std::string> helpers_type;
typedef std::map<string_key,by_size_type> by_key_type;
typedef std::map<string_key,std::string> helpers_type;

by_key_type by_key;
helpers_type helpers;
std::string root;

entry const &get_entry(std::string const &key,size_t params_no,std::string const &full_url) const
entry const &get_entry(string_key const &key,size_t params_no,string_key const &full_url) const
{
by_key_type::const_iterator kp = by_key.find(key);
if(kp == by_key.end())
throw cppcms_error("url_mapper: key `" + key + "' not found for "
"url `" + full_url + "'");
throw cppcms_error("url_mapper: key `" + key.str() + "' not found for "
"url `" + full_url.str() + "'");
by_size_type::const_iterator sp = kp->second.find(params_no);
if(sp == kp->second.end())
throw cppcms_error("url_mapper: invalid number of parameters for " + key +
"in url `" + full_url + "'");
throw cppcms_error("url_mapper: invalid number of parameters for " + key.str() +
"in url `" + full_url.str() + "'");
return sp->second;
}
url_mapper *is_app(std::string const &key) const
url_mapper *is_app(string_key const &key) const
{
by_key_type::const_iterator kp = by_key.find(key);
if(kp == by_key.end())
@@ -76,52 +103,44 @@ namespace cppcms {
return 0;
}

url_mapper &child(std::string const &name,std::string const &full_url)
url_mapper &child(string_key const &name,string_key const &full_url)
{
entry const &fmt = get_entry(name,1,full_url);
if(!fmt.child) {
throw cppcms_error("url_mapper: the key " + name + " is not child application key"
" in url `" + full_url + "'");
throw cppcms_error("url_mapper: the key " + name.str() + " is not child application key"
" in url `" + full_url.str() + "'");
}
return fmt.child->mapper();
}

void map( std::string const &key,
std::string const &full_url,
struct map_stream {
filters::streamable const * const *params;
size_t params_no;
std::map<string_key,std::string> const &data_helpers_default;
std::map<string_key,std::string> const &data_helpers_override;
};

void write( entry const &formatting,
filters::streamable const * const *params,
size_t params_no,
std::map<std::string,std::string> const &data_helpers_default,
std::map<std::string,std::string> const &data_helpers_override,
std::ostream &output) const
std::map<string_key,std::string> const &data_helpers_default,
std::map<string_key,std::string> const &data_helpers_override,
std::ostream &out) const
{
entry const &formatting = get_entry(key,params_no,full_url);
std::ostringstream ss;
std::ostream *out = 0;

if(parent) {
ss.copyfmt(output);
out = &ss;
}
else {
out = &output;
*out << root;
}

for(size_t i=0;i<formatting.parts.size();i++) {
*out << formatting.parts[i];
out << formatting.parts[i];
if( i < formatting.indexes.size() ) {
if(formatting.indexes[i]==0) {
std::string const &hkey = formatting.keys[i];
std::map<std::string,std::string>::const_iterator p;
p = data_helpers_override.find(hkey);
string_key hkey = string_key::unowned(formatting.keys[i]);
std::map<string_key,std::string>::const_iterator p;
p = data_helpers_override.find(string_key::unowned(hkey));
if(p != data_helpers_override.end()) {
*out << p->second;
out << p->second;
}
else {
p = data_helpers_default.find(hkey);
if(p!=data_helpers_default.end())
*out << p->second;
out << p->second;
}
}
else {
@@ -129,21 +148,46 @@ namespace cppcms {
if(index >= params_no) {
throw cppcms_error("url_mapper: Index of parameter out of range");
}
(*params[index])(*out);
(*params[index])(out);
}
}
}
}

void map( string_key const &key,
string_key const &full_url,
filters::streamable const * const *params,
size_t params_no,
std::map<string_key,std::string> const &data_helpers_default,
std::map<string_key,std::string> const &data_helpers_override,
std::ostream &out) const
{
entry const &formatting = get_entry(key,params_no,full_url);

if(parent) {
std::string url = ss.str();
stream_it<data,entry> url =
{
this,
formatting,
params,
params_no,
data_helpers_default,
data_helpers_override
};

filters::streamable stream_url(url);
filters::streamable const *par_ptr=&stream_url;
parent->mapper().d->map(this_name,full_url,&par_ptr,1,data_helpers_default,data_helpers_override,output);
parent->mapper().d->map(this_name,full_url,&par_ptr,1, data_helpers_default,
data_helpers_override,out);
}
else {
out << root;
write(formatting,params,params_no,data_helpers_default,data_helpers_override,out);
}

}


};

void url_mapper::assign(std::string const &key,std::string const &url)
@@ -268,8 +312,8 @@ namespace cppcms {
app.mapper().d->this_name = name;
real_assign(name,url,&app);
// Copy all values to root most one
std::map<std::string,std::string> &values = app.mapper().d->helpers;
std::map<std::string,std::string>::const_iterator p;
std::map<string_key,std::string> &values = app.mapper().d->helpers;
std::map<string_key,std::string>::const_iterator p;
for(p=values.begin();p!=values.end();++p) {
set_value(p->first,p->second);
}
@@ -295,7 +339,7 @@ namespace cppcms {
}


url_mapper &url_mapper::get_mapper_for_key(std::string const &key,std::string &real_key,std::vector<std::string> &keywords)
url_mapper &url_mapper::get_mapper_for_key(string_key const &key,string_key &real_key,std::vector<string_key> &keywords)
{
url_mapper *mapper = this;
size_t pos = 0;
@@ -312,15 +356,16 @@ namespace cppcms {
if(end == std::string::npos) {
size_t separator = key.find(';',pos);
if(separator == std::string::npos) {
real_key = key.substr(pos);
real_key = key.unowned_substr(pos);
}
else {
real_key = key.substr(pos,separator - pos);
keywords.reserve(6);
real_key = key.unowned_substr(pos,separator - pos);
pos = separator + 1;
for(;;){
end = key.find(',',pos);
size_t size = end - pos;
keywords.push_back(key.substr(pos,size));
keywords.push_back(key.unowned_substr(pos,size));
if(end == std::string::npos)
break;
pos = end + 1;
@@ -343,13 +388,13 @@ namespace cppcms {
return *mapper;
}
size_t chunk_size = end - pos;
if(key.compare(pos,chunk_size,".") == 0)
string_key subapp = key.unowned_substr(pos,chunk_size);
if(subapp == ".")
; // Just continue where we are
else if(key.compare(pos,chunk_size,"..")==0) {
else if(subapp == "..") {
mapper = &mapper->parent();
}
else {
std::string subapp = key.substr(pos,chunk_size);
mapper = &mapper->d->child(subapp,key);
}
pos = end + 1;
@@ -357,17 +402,18 @@ namespace cppcms {
}


void url_mapper::real_map( std::string const &key,
void url_mapper::real_map( char const *ckey,
filters::streamable const * const *params,
size_t params_no,
std::ostream &output)
{
std::string real_key;
std::vector<std::string> direct;
string_key key=string_key::unowned(ckey);
string_key real_key;
std::vector<string_key> direct;
url_mapper &mp = get_mapper_for_key(key,real_key,direct);
if(params_no < direct.size())
throw cppcms_error("url_mapper: number of keywords is larger then number of actual parameters");
std::map<std::string,std::string> mappings;
std::map<string_key,std::string> mappings;
if(direct.size() == 0) {
mp.d->map(real_key,key,params,params_no,topmost().d->helpers,mappings,output);
}
@@ -385,23 +431,86 @@ namespace cppcms {
mp.d->map(real_key,key,params,params_no,topmost().d->helpers,mappings,output);
}
}
void url_mapper::map( std::ostream &out,
std::string const &key)
{
real_map(key,0,0,out);
map(out,key.c_str());
}

void url_mapper::map( std::ostream &out,
std::string const &key,
filters::streamable const &p1)
{
map(out,key.c_str(),p1);
}

void url_mapper::map( std::ostream &out,
std::string const &key,
filters::streamable const &p1,
filters::streamable const &p2)
{
map(out,key.c_str(),p1,p2);
}

void url_mapper::map( std::ostream &out,
std::string const &key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3)
{
map(out,key.c_str(),p1,p2,p3);
}

void url_mapper::map( std::ostream &out,
std::string const &key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
filters::streamable const &p4)
{
map(out,key.c_str(),p1,p2,p3,p4);
}

void url_mapper::map( std::ostream &out,
std::string const &key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
filters::streamable const &p4,
filters::streamable const &p5)
{
map(out,key.c_str(),p1,p2,p3,p4,p5);
}

void url_mapper::map( std::ostream &out,
std::string const &key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
filters::streamable const &p4,
filters::streamable const &p5,
filters::streamable const &p6)
{
map(out,key.c_str(),p1,p2,p3,p4,p5,p6);
}

void url_mapper::map( std::ostream &out,
char const *key)
{
real_map(key,0,0,out);
}

void url_mapper::map( std::ostream &out,
char const *key,
filters::streamable const &p1)
{
filters::streamable const *params[1]= { &p1 };
real_map(key,params,1,out);
}

void url_mapper::map( std::ostream &out,
std::string const &key,
char const *key,
filters::streamable const &p1,
filters::streamable const &p2)
{
@@ -410,7 +519,7 @@ namespace cppcms {
}

void url_mapper::map( std::ostream &out,
std::string const &key,
char const *key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3)
@@ -420,7 +529,7 @@ namespace cppcms {
}

void url_mapper::map( std::ostream &out,
std::string const &key,
char const *key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
@@ -431,7 +540,7 @@ namespace cppcms {
}

void url_mapper::map( std::ostream &out,
std::string const &key,
char const *key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,
@@ -443,7 +552,7 @@ namespace cppcms {
}

void url_mapper::map( std::ostream &out,
std::string const &key,
char const *key,
filters::streamable const &p1,
filters::streamable const &p2,
filters::streamable const &p3,


+ 38
- 11
src/util.cpp View File

@@ -20,6 +20,7 @@
#include <cppcms/util.h>
#include "http_protocol.h"
#include <stdio.h>
#include <iterator>
#include "md5.h"

namespace cppcms {
@@ -43,18 +44,31 @@ std::string escape(std::string const &s)
return content;
}

std::string urlencode(std::string const &s)

void escape(char const *begin,char const *end,std::ostream &output)
{
std::string content;
unsigned i,len=s.size();
content.reserve(3*len);
for(i=0;i<len;i++){
char c=s[i];
while(begin!=end) {
char c=*begin++;
switch(c){
case '<': output << "&lt;"; break;
case '>': output << "&gt;"; break;
case '&': output << "&amp;"; break;
case '\"': output<<"&quot;"; break;
default: output << c;
}
}
}

template<typename Iterator>
void urlencode_impl(char const *b,char const *e,Iterator out)
{
while(b!=e){
char c=*b++;
if( ('a'<=c && c<='z')
|| ('A'<=c && c<='Z')
|| ('0'<=c && c<='9'))
{
content+=c;
*out++ = c;
}
else {
switch(c) {
@@ -62,20 +76,33 @@ std::string urlencode(std::string const &s)
case '_':
case '.':
case '~':
content+=c;
*out++ = c;
break;
default:
{
static char const hex[]="0123456789abcdef";
unsigned char uc = c;
content += '%';
content += hex[(uc >> 4) & 0xF];
content += hex[ uc & 0xF];
*out++ = '%';
*out++ = hex[(uc >> 4) & 0xF];
*out++ = hex[ uc & 0xF];
}
};
}
};
}

void urlencode(char const *b,char const *e,std::ostream &out)
{
std::ostream_iterator<char> it(out);
urlencode_impl(b,e,it);
}
std::string urlencode(std::string const &s)
{
std::string content;
content.reserve(3*s.size());
std::back_insert_iterator<std::string> out(content);
urlencode_impl(s.c_str(),s.c_str()+s.size(),out);
return content;
}



Loading…
Cancel
Save