Coding Standards for CppCMS 1.x.x
Coding Style
- Indentation: --- K&R only.
Naming: use small_letters_and_underscore. Such names are much more readable. Same naming convention for class names, variables and functions. NeverUseUglyAndUnreadableCamelCasedCode. Rationale -- readability.
Prefer to use STL conventions. For example, for cleanup operations use
clear()
, for finding something "find()" and so on.- Polish/Hungarian notations are not in CppCMS. No prefixes or suffixes like
iNumber
orm_some_class_member
. Variable Names: --- variables like
i
,j
,tmp
are perfectly well to use inside functions, in loops. It is ok to usedef
,tmp
prefixes and suffixes for member variables when they meaning something.Rationale: Linux Kernel Coding Style.
Class Members: are ended with underscore
_
with exception of public structure members that do not have suffixes/prefixes.Getters and Setters should have same name but without underscore at the end. For example:
class foo { public: int bar(); // getter void bar(int x); // setter private: int bar_; };
When using d-pointer, not not put underscore at the end of
data
structure members -- as it is structure with public members.using namespace
-- is fine for C++ source files: (a.k.a. cpp). but it should be never used in header files even it is annoying to writestd::
many times.Tab Stops --- Tab is 8, not 4, not 2 and defiantly not 5! Tab width=8 is like Pi=3.1415926535. Do not use something else. This is most compatible over different editors, it is standard, it should be used anywhere. It makes code more readable at 1:00am.
Do not replace tabs with spaces, all indentation should be done with tabs.
Rationale: Linux Kernel Coding Style
Preprocessor Macros --- should be CAPITAL_CASED_WITH_UNDERSCORES. Always add
CPPCMS_
prefix to them.
General Coding Notes
Exceptions
All code you write should be exception safe. Only functions that you may assume they never throw exceptions are POSIX API or 3rd party C libraries like libgcrypy or sqlite3. Even STL may throw exception. Assume that std::bad_alloc may be thrown and handle it correctly.
Thus:
Always use smart pointers. Prefer auto_ptr over reference counting smart pointers:
- It is faster and does not include ref-counting overheads
- All of them can be always created from auto_ptr but not in other direction.
- It has move semantics that covers our requirements in most of cases:
For example
auto_ptr<my_class> my_func() { auto_ptr<my_class> instance(new my_class); instance->do_something(); return instance; }
Use std::vector instead of allocating
new some_class[N]
.- When using C API, that does not have destructors, put your code inside try-catch block and cleanup everything.
- If you use C API in more then one place consider wrapping it with simple class or at least provide scoped destructor. See as an example posix_mutex.h or fcntl_mutex.h
STL
Do not reinvent the wheel, use STL --- it is well document, well known, highly available library that does the job. Use it.
Notes:
- Always prefer std::vector to std::list --- it has better performance because it is cache friendly.
- Always prefer std:string for text storage.
- It is OK to return STL collections from functions, compiler know how to optimize them - return value optimization (RVO).
Do not forget
swap()
function --- it can save lot's of unnecessary copies for you. For example:vector<char> foo(); ... void bar() { vector<char> s; for(;;) { // RVO vector<char> result = foo(); // move s.swap(result); if(s.empty()) break; } }
Description: when you call
s=foo()
assignment operator is called that copies the value thatfoo()
returned tos
and then releases it. When you calls.swap(foo())
the value ins
is replaced by returned value and the old value ins
is cleaned --- you saved copy of probably huge buffer, you operation is done inO(1)
.- If you have non-copyable class, you can store it in STL collection using reference counting pointer.
Libraries
Boost
CppCMS does not use Boost!
It uses either Booster library that uses Boost-Like API
or it uses cppcms_boost
- renamed Boost library hidden
from the user deep inside.
Rationale:
Boost does not provide any backward compatibility between releases and tend to break something every three month.
And of course there is no even such thing like ABI compatibility when we talk about Boost.
So the only way to use it - use renamed cppcms_boost
.
Booster
Booster is backward compatible, ABI stable CppCMS's Boost that can be and should be used in CppCMS's API.
It already has: aio (asio like library), threads, regex, function, POSIX-time, localization, smart_pointers, system, and logging library.
Of course it is only a small subset of what Boost provides
but it covers 95% of what CppCMS needs from Boost. The rest
can be found in hidden cppcms_boost
namespace (see previous section)
Note. Booster is not exact subset of Boost as it re-implements some features in different way: Booster.Regex uses PCRE, AIO is quite different from Asio, Booster.Thread is build on top of pthreads library.
Also there are some libraries that not persistent or extremely different or simplified: Booster.Locale, Booster.Nowide, Booster.AIO, Booster.Log and so on.
The general rule of Booster - make API as similar as possible to Boost onces, but do it in simple and robust way.
Licenses
- All libraries should be OpenSource libraries
- Prefer non-copyleft licenses like MIT, 3 clause BSD, Boost over copyleft one, like LGPL.
- All libraries, CppCMS uses should be compatible with LGPLv3.
You may use strong copyleft libraries for stand alone utilities that are not linked with CppCMS framework.
For example: If you want to write GUI for
cppcms_tcp_scale
utility using Qt you are welcome.
Using
If you want to add an additional dependency for CppCMS make sure:
- Check if boost has implementation of such feature.
- There is a big value for adding such dependency.
- This library is highly available.
- You checked all alternatives and decided that this one is the best.
- You had added a CMake macro and conditional build for CppCMS that allows building all framework without this library.
For example, libgcrypt:
- You need high quality library to encrypt cookies, home made solutions are too dangerous.
- This library is available for almost any UNIX platform.
- Other alternatives like OpenSSL has problematic license and bad documentation.
- If you do not have libgcrypt, you still have simple digitally signed cookies that are still safe.
Keeping backward compatible ABI
One of the major goals of CppCMS is keeping stable backward compatible API and ABI the way it is done in Qt framework. This is not simple task to do in C++. So in order to achieve this goal following should be done:
- All user API should use only standard naively supported C++ classes and libraries -- STL.
- No 3rd part libraries API should be ever exposed to user -- including but not limited to -- Boost.
- All classes with exception of extremely simple ones with very limited and well defined functionality should include opaque pointer in order to ensure that adding or removing class member would break ABI.
This is a very good reference written for KDE on how not to break ABI. READ IT!!!
How to write classes
- Any class, with exception of very trivial and very simple should have a d-pointer or pimpl pointer.
- All constructors and destructors should be non-inline.
- If the class in copyable implement non-inline copy
constructor and assignment operator, otherwise make
them private or derive from
booster::noncopyable
. - Use
booster::copy_ptr
for d-pointers of copyable classes andbooster::hold_ptr
for d-pointers of noncopyable classes. Prefer them overauto_ptr
because the have same const semantics for them and the data that is pointed by them. - Prefer to hide the content of "d" pointer from user,
this would allow adding types that are not known to
user like
boost::io::tcp::socket
. - Always provide getters/setters for properties -- you should never expose class data members to user unless you have very good reason.
For example:
Header:
// foo.h class foo : public booster::noncopyable { public: foo(); // Always should be non-inlined constructor ~foo(); // Always should be non-inlined destructor int x() const; // getter void x(int ); // setter private: struct data; booster::hold_ptr<data> d; };
Implementation:
// foo.cpp struct foo::data { int x; }; foo::foo() : d(new foo::data()) { } foo::~foo() { } int foo::x() const { return d->x; } void foo::x(int v) { d->x=v; }
F.A.Q.
But how can I use (Put Boost Library Name) in the code?
Use it, just never expose it in user API.
What about
boost::signal
?Wrap a linked list of
booster::function
with your favorite API.What about
boost::bind
?Are you sure you need to use bind in headers?
If so, there are simple member function binders implemented in mem_bind.h. If it not suit your needs just create simple copyable class with
operator()
.
Internationalization and Localization
Keep in mind that this project should support many languages and cultures -- thus be aware of this.
The major gateway to localization facilities is std::locale
class with custom facets assigned to http::context
and to std::ostream
of HTML output.
Be aware:
If you write some data to output stream you may get not what you expect. For example:
response().out()<<"<div style='font-size:" <<1.5<<"%'>"
You may get (with comma instead of dot)
<div style='font-size:1,5%'>
Instead of:
<div style='font-size:1.5%'>
User may define global locale thus you may get similar artifacts calling
boost::lexical_cast
.So, anytime you create some output that should be readable by machine make sure you use C locale.
out<<boost::format("width='%1%'",std::locale::classic()) % width_.
Same for all locale dependent stuff like
toupper
that may accidentally convert<div>
to<DİV>
instead of<DIV>
-- not exactly what you expect.
Other points:
CppCMS should be optimized for UTF-8 as internal text representation but other character encodings like 8 bit "latin1" should be fully supported as well.
Never display text directly, allow user translate it using gettext, or try using language agnostic marks, like "*" for marking error instead of writing message directly.
- Never assume anything culture related. Even quotation marks may differ between various cultures.
- All text processing facilities should be done using
facets of
std::locale
class.
Windows Specific Notes
Windows does not support UTF-8 codepage, so any-time you need to use system API you need to use so-called "Wide" API.
Of course neither C nor C++ standard does not provide such stuff like Wide API.
So, the policy is following:
- All strings under windows are assumed UTF-8 strings.
- When you call Windows specific API functions always use Wide one explicitly. For example DeleteFileW.
- Use
booster::nowide::convert()
functions to convert between UTF-8 and Wide UTF-16 string before passing them to these functions. For standard C and C++ library functions (without "Wide" alternatives) use
booster::nowide
implementations wich provide access tostdio
's UTF-8 enabledfopen
,remove
,rename
and STL'sfstream
.So when you write generic code that opens file you should use:
booster::nowide::ifstream file("myfile.txt");
Instead of
std::ifstream file("myfile.txt");
Under "normal" operating system it would be just alias for
std::*
functions and classes and under Windows it would provide UTF-8 enabled implementations.
Copyrights
I hope that someday this project would have commercial basis. In such case I need to have an ability to sub-license it. I do not mean that CppCMS may become closed sources project, it is and will remain FOSS framework with weak copyleft license like LGPL.
However for certain situation I would need an ability to provide additional licensing for this, like this is done by LGPL Qt4 and many other FOSS projects.
Thus every code contributed to CppCMS should hold at least one of the following conditions:
- Licensed under permissive non-copyleft license compatible with LGPLv3: like MIT, Boost, 3 clause BSD.
- The copyrights on the source code would be transferred to project owner.
This would give CppCMS an opportunity to become successful FOSS project.
Clarification:
- I believe in Open Source and CppCMS would always be Free Software project.
- The CppCMS source code would be distributed under weak copyleft license allowing development of commercial software with CppCMS without fees.