Files
contract/example/str/str.cpp
2017-08-28 20:51:08 -07:00

133 lines
4.3 KiB
C++
Executable File

/**
* @file
* @author Copyright (C) 2009 Lorenzo Caminiti.
* Distributed under DBC++ Software License (see file LICENSE_1_0.txt).
*/
#include <dbc.hpp>
#include <cstring>
#include <iostream>
/**
* Demonstrate the use of Design By Contract for C++ macro-based API
* implementing a simple string type.
* @see "example/str/str-codeapi.cpp" for same example using code-based API.
*/
class str DBC_INHERIT_OBJECT(str) { // Derive from dbc::object.
public:
/** Max limit on string length. */
static const size_t MAX_SIZE = 16000;
/**
* Construct from C-style null-terminated string.
* @param[in] chars C-style null-terminated string.
*/
str(const char* chars): size_(), chars_()
DBC_CONSTRUCTOR( (public) (str)( (const char*)(chars) ), {
// Constructor preconditions.
size_t size = strlen(chars); // Code allowed but keep it simple.
// Use DBC_ASSERT() or DBC_ASSERT_STREAM() to assert conditions.
DBC_ASSERT(size >= 0 && size < str::MAX_SIZE, "size in range");
}, {
// Constructor postconditions.
DBC_ASSERT(self.now.size() == strlen(chars.now), "size set");
DBC_ASSERT(strncmp(self.now.chars_, chars.now,
self.now.size()) == 0, "chars set");
}, {
// Constructor body.
size_ = strlen(chars);
chars_ = new char[size_];
strncpy(chars_, chars, size_);
})
/**
* Copy constructor.
* Copy constructor is used by library to support "old" in postcond. User
* defined copy constr is needed for pointer deep copy.
* @note To avoid code duplication, this and the above constructor could
* be refactored delegating implementation and contract to an init() func.
* @param[in] other Other string object.
*/
str(const str& other): size_(), chars_()
DBC_CONSTRUCTOR( (public) (str)( (const str&)(other) ), {
// Use other.size() not other.size_ as precond should use public member.
DBC_ASSERT(other.size() >= 0 && other.size() < str::MAX_SIZE,
"size in range");
}, {
DBC_ASSERT(self.now.size() == other.now.size(), "size set");
DBC_ASSERT(strncmp(self.now.chars_, other.now.chars_,
self.now.size()) == 0, "chars set");
}, {
delete[] chars_;
size_ = other.size_;
chars_ = new char[size_];
strncpy(chars_, other.chars_, size_);
})
/** Destroy. */
virtual ~str(void)
DBC_DESTRUCTOR( (public) (virtual) (str)( (void) ), {
// Destructor body.
delete[] chars_; // Invariant already checked chars_ != 0.
})
/**
* Return character at specified index.
* @param[in] index Index position.
* @return str's character at specified position.
*/
char& operator[](const size_t& index)
DBC_MEM_FUN( (public) (char&) DBC_COPYABLE(str)
(operator_at)( (const size_t&)(index) ), {
// Member function preconditions.
DBC_ASSERT(index >= 0 && index < self.size(), "index in range");
}, {
// Member function postconditions.
// Not a const mem fun, use 'self.old' for object before body and
// make class type DBC_COPYABLE().
DBC_ASSERT(result == self.old.chars_[index.now],
"returning char at index");
}, {
// Member function body.
return chars_[index];
})
/**
* Return size (total number of characters).
* @return str's size.
*/
size_t size(void) const
DBC_MEM_FUN( (public) (size_t) (str) (size)( (void) ) (const), {
}, {
DBC_ASSERT(result == self.now.size_, "returning size");
}, {
return size_;
})
private:
/** Internal string size. */
size_t size_; // Unsgined so size_ >= 0 check could be removed...
/** Internal string representation. */
char* chars_;
DBC_INVARIANT(str, {
// Invariants.
DBC_ASSERT(self.chars_ != 0, "chars exist");
DBC_ASSERT(self.size_ >= 0 && self.size_ < str::MAX_SIZE,
"size in range");
})
};
/** Main program. */
int main() {
std::cout << std::endl << "init()..." << std::endl;
str s("Galileo Galilei");
std::cout << std::endl << "operator[](0)..." << std::endl;
std::cout << s[0] << std::endl;
std::cout << std::endl << "del()..." << std::endl;
return 0;
}