- [Coding Style](#cs) |
- [General Coding Notes](#cn) |
- [Exceptions](#exceptions) |
- [STL](#stl) |
- [Libraries](#libraries) |
- [Boost](#boost) |
- [Using](#using) |
- [Keeping backward compatible ABI](#abi) |
- [How to write classes](#write_class) |
- [F.A.Q.](#abi_faq) |
- [Using Boost](#abi_boost) |
- [Internationalization and Localization](#locale) |
|
|
## <span id="cs"></span>Coding Style |
|
- **Indentation:** --- K&R only. |
- **Naming:** use small\_letters\_and\_underscore. Such names are much more |
readable. Same namging 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` or `m_some_class_member`. |
- **Variable Names:** --- variables like `i`, `j`, `tmp` are perfrectly well to use inside functions, in loops. |
It is ok to use `def`, `tmp` perfixes 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 write `std::` 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. |
|
|
|
|
## <span id="cn"></span>General Coding Notes |
|
### <span id="exceptions"></span>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: |
|
1. It is faster and does not include ref-counting overheads |
2. All of them can be always created from auto\_ptr but not in other direction. |
3. 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 |
|
### <span id="stl"></span>STL |
|
Do not reinvent the wheel, use STL --- it is well document, well known, highly available library that does the job. Use it. |
|
_Notes:_ |
|
1. Always prefer std::vector to std::list --- it has better performance because it is cache friendly. |
2. Always prefer std:string for text storage. |
3. It is OK to return STL collections from functions, compiler know how to optimize them. |
4. 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(;;) { |
s.swap(foo()); |
// Not s=foo(); |
if(s.empty()) |
break; |
} |
} |
|
Description: when you call `s=foo()` assignment operator is called that copies the value that `foo()` returned to `s` and then releases it. When you call `s.swap(foo())` the value in `s` is replaced by returned value and the old value in `s` is cleaned --- you saved copy of probably huge buffer, you operation is done in `O(1)`. |
5. If you have non-copyable class, you can store it in STL collection using reference counting pointer. |
|
## <span id="libraries"></span>Libraries |
|
### <span id="boost"></span>Boost |
|
CppCMS should work with at least Boost 1.36. |
|
Generally prefer boost over other libraries, however use Boost features carefully, or do not use at all. Examples: |
|
1. Boost Interprocess too "heavy" and little bit "ugly" because it supports windows and supports placing any objects in memory. The nature of `fork()` gives much better functionality and allows placing any object in shared memory every time it use shared memory allocators. |
|
So use it only as replacement of libmm. |
|
3. Boost Serialization -- has too many performance overheads -- don't use it. |
|
### <span id="lic"></span>Licenses |
|
1. All libraries should be OpenSource libraries |
2. Prefer non-copyleft licenses like MIT, 3 clause BSD, Boost over copyleft one, like LGPL. |
3. All libraries, CppCMS uses should be compatible with LGPLv2. |
4. 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. |
|
|
### <span id="using"></span>Using |
|
If you want to add an additional dependency for CppCMS make sure: |
|
1. Check if boost has implementation of such feature. |
1. There is a big value for adding such dependency. |
2. This library is highly available. |
3. You checked all alternatives and decided that this one is the best. |
4. You had added an autoconf 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. |
|
## <span id="abi"></span>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: |
|
1. All user API should use only standard natively supported C++ classes and libraries -- STL. |
2. No 3rd part libraries API should be ever exposed to user -- including but not limited to -- [Boost](http://www.boost.org). |
3. 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](http://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++) written for KDE on how not to break ABI. **READ IT!!!** |
|
### <span id="write_class"></span>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 `util::noncopyable`. |
- Use `util::copy_ptr` for d-pointers of copyable classes |
and `util::hold_ptr` for d-pointers of noncopyable |
classes. Prefer them over `auto_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 util::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; |
util::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; } |
|
### <span id="abi_faq"></span>F.A.Q. |
|
1. _But how can I use (Put Boost Library Name) in the code?_ |
|
Use it, just never expose it in user API. |
|
2. _But how can I write callbacks without `boost::function`_? |
|
Use internal simple implementation of `callbackX.h` it provides most of functionality. |
|
3. _What about `boost::signal`?_ |
|
Wrap a linked list of callbacks with your favorite API. |
|
4. _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()`. |
|
5. _What about `boost::shared_ptr`?_ |
|
Unfortunately boost implementation of `shared_ptr` has |
some issues for keeping ABI -- the reference counter |
implementation depended on some macros, so simple |
`define` may break ABI if `shared_ptr` is disclosed |
to user. Also, C++0x `shared_ptr` is still not widely |
supported. So you can't use `shared_ptr` in CppCMS API. |
|
6. _Where do I get reference counting smart pointers for CppCMS?_ |
|
CppCMS had grabbed local copy of `boost::intrusive_ptr` |
and implemented thread-safe atomic counter that |
is kept ABI safe. |
|
So any class that should be used with reference counting |
can be simply derived from `refcounted` class that |
provides expected functionality. |
|
`intrusive_ptr` is not as powerful as `shared_ptr` |
because it lacks weak references, but it is good |
enough for most of cases, also, its flexibility |
allows keeping finer semantics -- for example, you |
may not destroy the object but recycle it to pool |
like it is done for `cppcms::application`. |
|
1. _But I need to expose (Put Library Name) to user?_ |
|
Wrap it. See for example regex.h and regex.cpp --- |
wrapping `boost::regex`. |
|
### <span id="abi_boost"></span>Using Boost |
|
CppCMS relates on Boost but it does not provide backward |
ABI or even API compatibility... So how should you deal with it? |
|
At this point, CppCMS links with specific version of Boost |
library and enforces user to use exactly same version of |
Boost. |
|
Very soon it would be changed. CppCMS would use its local |
version of Boost where all namespaces are renamed to |
other namespace like `cppcms_boost` in order to prevent |
collision woth other Boost versions. |
|
Thus CppCMS would be shipped with its own version of Boost |
libraries and its upgrade would be transparent to user. |
|
## <span id="locale"></span>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. |
- Prefer using ICU over standard C++ locale facets (if |
available). |
|