├── README ├── scpp_array.hpp ├── scpp_assert.cpp ├── scpp_assert.hpp ├── scpp_date.cpp ├── scpp_date.hpp ├── scpp_matrix.hpp ├── scpp_ptr.hpp ├── scpp_refcountptr.hpp ├── scpp_scopedptr.hpp ├── scpp_types.hpp └── scpp_vector.hpp /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladimir-kushnir/SafeCPlusPlus/f5f161808d638a90e6a3919f8d91b4e0048c7f07/README -------------------------------------------------------------------------------- /scpp_array.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladimir-kushnir/SafeCPlusPlus/f5f161808d638a90e6a3919f8d91b4e0048c7f07/scpp_array.hpp -------------------------------------------------------------------------------- /scpp_assert.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Safe C++, Or How to Avoid Most Common Mistakes in C++ Code 4 | by Vladimir Kushnir, (O’Reilly). 5 | 6 | Copyright 2012 Vladimir Kushnir, ISBN 9781449320935. 7 | 8 | If you feel your use of code examples falls outside fair use or the 9 | permission given above, feel free to contact us at permissions@oreilly.com. 10 | 11 | */ 12 | 13 | #include "scpp_assert.hpp" 14 | 15 | #include // cerr, endl, flush 16 | #include // exit() 17 | 18 | 19 | using namespace std; 20 | 21 | #ifdef SCPP_THROW_EXCEPTION_ON_BUG 22 | namespace scpp { 23 | ScppAssertFailedException::ScppAssertFailedException(const char* file_name, 24 | unsigned line_number, 25 | const char* message) { 26 | ostringstream s; 27 | s << "SCPP assertion failed with message '" << message 28 | << "' in file " << file_name << " #" << line_number; 29 | 30 | what_ = s.str(); 31 | } 32 | } 33 | #endif 34 | 35 | void SCPP_AssertErrorHandler(const char* file_name, 36 | unsigned line_number, 37 | const char* message) { 38 | // This is a good place to put your debug breakpoint: 39 | // You can also add writing of the same info into a log file if appropriate. 40 | 41 | #ifdef SCPP_THROW_EXCEPTION_ON_BUG 42 | throw scpp::ScppAssertFailedException(file_name, line_number, message); 43 | #else 44 | cerr << message << " in file " << file_name << " #" << line_number << endl << flush; 45 | // Terminate application 46 | exit(1); 47 | #endif 48 | } 49 | -------------------------------------------------------------------------------- /scpp_assert.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladimir-kushnir/SafeCPlusPlus/f5f161808d638a90e6a3919f8d91b4e0048c7f07/scpp_assert.hpp -------------------------------------------------------------------------------- /scpp_date.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Safe C++, Or How to Avoid Most Common Mistakes in C++ Code 4 | by Vladimir Kushnir, (O’Reilly). 5 | 6 | Copyright 2012 Vladimir Kushnir, ISBN 9781449320935. 7 | 8 | If you feel your use of code examples falls outside fair use or the 9 | permission given above, feel free to contact us at permissions@oreilly.com. 10 | 11 | */ 12 | 13 | #include "scpp_date.hpp" 14 | 15 | #include // strlen 16 | #include // atoi 17 | 18 | namespace scpp { 19 | Date::Date() 20 | : date_(0) 21 | { 22 | #ifdef _DEBUG 23 | yyyymmdd_ = 0; 24 | #endif 25 | } 26 | 27 | Date::Date(const char* str_date) { 28 | SCPP_ASSERT(str_date!=NULL, "Date(): string argument=0.") 29 | 30 | // must be mm/dd/yyyy, at least m/d/yyyy 31 | SCPP_TEST_ASSERT(strlen(str_date)>=8, "Bad Date input: '" << str_date << "'.") 32 | 33 | unsigned mm, dd=0, yyyy=0; 34 | 35 | mm = atoi(str_date); 36 | for(const char* p=str_date; (*p)!='\0'; ++p) { 37 | if(*p=='/') { 38 | if(dd==0) 39 | dd = atoi(p+1); 40 | else { 41 | yyyy = atoi(p+1); 42 | break; 43 | } 44 | } 45 | } 46 | 47 | SCPP_TEST_ASSERT(mm!=0 && dd!=0 && yyyy!=0, "Bad Date input '" << str_date << "', must be MM/DD/YYYY."); 48 | 49 | *this = Date(yyyy, mm, dd); 50 | } 51 | 52 | Date::Date(const std::string& str) { 53 | *this = Date(str.c_str()); 54 | } 55 | 56 | Date::Date(unsigned yyyymmdd) { 57 | int yyyy = yyyymmdd / 10000; 58 | int mmdd = yyyymmdd - 10000 * yyyy; 59 | int mm = mmdd / 100; 60 | int dd = mmdd - 100 * mm; 61 | 62 | *this = Date(yyyy, mm, dd); 63 | } 64 | 65 | Date::Date(unsigned year, unsigned month, unsigned day) { 66 | SCPP_TEST_ASSERT(year>=1900, "Year must be >=1900.") 67 | SCPP_TEST_ASSERT(JAN<=month && month<=DEC, "Wrong month " << month << " must be 1..12.") 68 | #ifdef SCPP_TEST_ASSERT_ON 69 | unsigned ml = MonthLength(month, year); 70 | SCPP_TEST_ASSERT(1<=day && day<=ml, "Wrong day: " << day << " must be 1.." << ml << "."); 71 | #endif 72 | int n_years_before = year-1; 73 | date_ = 365*n_years_before 74 | + n_years_before/4 - n_years_before/100 + n_years_before/400 75 | + day + NumberOfDaysBeforeMonth(month, year); 76 | 77 | SyncDebug(year, month, day); 78 | } 79 | 80 | unsigned Date::AsYYYYMMDD() const { 81 | unsigned y = Year(); 82 | unsigned m = Month(); 83 | unsigned d = Data() - Date(y, m, 1).Data() + 1; 84 | 85 | return y*10000 + m*100 + d; 86 | } 87 | 88 | bool Date::IsLeap(unsigned year) { 89 | if(year%4) 90 | return false; 91 | 92 | if(year%400 == 0) 93 | return true; 94 | 95 | if(year%100 == 0) 96 | return false; 97 | 98 | return true; 99 | } 100 | 101 | Date::DayOfWeekType Date::DayOfWeek() const { 102 | return (DayOfWeekType)(date_ % 7); 103 | } 104 | 105 | const char* Date::DayOfWeekStr() const { 106 | static const char* str_day_of_week[] = { 107 | "Sunday", "Monday", "Tuesday", "Wednesday", 108 | "Thursday", "Friday", "Saturday" }; 109 | 110 | DayOfWeekType dow = DayOfWeek(); 111 | return str_day_of_week[(unsigned)dow]; 112 | } 113 | 114 | // static 115 | unsigned Date::MonthLength(unsigned month, unsigned year) { 116 | static int month_length[13] = { 0, 31,28,31,30,31,30,31,31,30,31,30,31 }; 117 | SCPP_TEST_ASSERT(year>=1900, "Wrong year: " << year << ", must be >=1900."); 118 | SCPP_TEST_ASSERT(JAN <= month && month <= DEC, "Wrong month " << month); 119 | if(month == FEB && IsLeap(year)) 120 | return 29; 121 | return month_length[month]; 122 | } 123 | 124 | // static 125 | unsigned Date::NumberOfDaysBeforeMonth(unsigned month, unsigned year) { 126 | static int days_before_month[12] = { 0, 31,59,90,120,151,181,212,243,273,304,334 }; 127 | SCPP_TEST_ASSERT(year>=1900, "Wrong year: " << year << ", must be >=1900."); 128 | SCPP_TEST_ASSERT(JAN <= month && month <= DEC, "Wrong month " << month); 129 | unsigned days_before = days_before_month[month - 1]; 130 | if (month >= MAR && IsLeap(year)) 131 | ++days_before; 132 | return days_before; 133 | } 134 | 135 | unsigned Date::Year() const { 136 | SCPP_TEST_ASSERT(IsValid(), "Date is not valid") 137 | 138 | unsigned y = Data() / 365; 139 | while(Date(y,1,1).Data() > Data()) 140 | --y; 141 | return y; 142 | } 143 | 144 | unsigned Date::Month() const { 145 | SCPP_TEST_ASSERT(IsValid(), "Date is not valid") 146 | 147 | unsigned y = Year(); 148 | Date endOfLastYear(y-1, DEC, 31); 149 | unsigned day = Data() - endOfLastYear.Data(); 150 | for(unsigned m=JAN; m<=DEC; ++m) 151 | { 152 | unsigned ml = MonthLength(m, y); 153 | if(day <= ml) 154 | return m; 155 | day -= ml; 156 | } 157 | SCPP_ASSERT(false, "Fatal algorith error.") 158 | return 0; 159 | } 160 | 161 | unsigned Date::DayOfMonth() const { 162 | SCPP_TEST_ASSERT(IsValid(), "Date is not valid") 163 | 164 | unsigned y = Year(); 165 | unsigned m = Month(); 166 | unsigned d = Data() - Date(y, m, 1).Data() + 1; 167 | SCPP_TEST_ASSERT(d > 0 && d <= MonthLength(m,y), 168 | "Wrong day " << d << " of month " << m << " year " << y ); 169 | return d; 170 | } 171 | 172 | char* Date::AsString(char* buffer, unsigned bufLen, DateOutputFormat frmt) const { 173 | SCPP_TEST_ASSERT(IsValid(), "Date is not valid") 174 | SCPP_TEST_ASSERT(bufLen>=MIN_BUFFER_SIZE, 175 | "Buffer is too short: " << bufLen << " must be at least " << MIN_BUFFER_SIZE) 176 | 177 | unsigned y = Year(); 178 | unsigned m = Month(); 179 | unsigned d = Data() - Date(y, m, 1).Data() + 1; 180 | 181 | switch(frmt) { 182 | case FRMT_AMERICAN: 183 | sprintf(buffer, "%02d/%02d/%04d", m, d, y); 184 | break; 185 | 186 | case FRMT_EUROPEAN: 187 | sprintf(buffer, "%02d.%02d.%4d", m, d, y); 188 | break; 189 | 190 | default: 191 | SCPP_ASSERT(false, "Wrong output format " << frmt); 192 | } 193 | 194 | return buffer; 195 | } 196 | 197 | std::string Date::AsString(DateOutputFormat frmt) const { 198 | char buffer[ 12 ]; 199 | return AsString(buffer, sizeof(buffer), frmt); 200 | } 201 | } // namespace scpp 202 | 203 | -------------------------------------------------------------------------------- /scpp_date.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Safe C++, Or How to Avoid Most Common Mistakes in C++ Code 4 | by Vladimir Kushnir, (O’Reilly). 5 | 6 | Copyright 2012 Vladimir Kushnir, ISBN 9781449320935. 7 | 8 | If you feel your use of code examples falls outside fair use or the 9 | permission given above, feel free to contact us at permissions@oreilly.com. 10 | 11 | */ 12 | 13 | #ifndef __SCPP_DATE_HPP_INCLUDED__ 14 | #define __SCPP_DATE_HPP_INCLUDED__ 15 | 16 | #include 17 | #include 18 | 19 | #include "scpp_assert.hpp" 20 | #include "scpp_types.hpp" 21 | 22 | /* 23 | Date class. 24 | Features: 25 | All date arithmetic operators and comparisons are provided. 26 | Date arithmetic is implemented as an integer arithmetic. 27 | No Y2K problems -- all years must be >= 1900. 28 | Default output format is American (MM/DD/YYYY). 29 | In debug one can see the date in debugger as yyyymmdd -- 30 | just point your debugger to a yyyymmdd_ data member. 31 | 32 | No implicit type conversions are allowed. 33 | 34 | */ 35 | namespace scpp { 36 | class Date { 37 | public: 38 | // Creates an empty (invalid in terms of IsValid()) date. 39 | Date(); 40 | 41 | // Input format: "mm/dd/yyyy". 42 | explicit Date(const char* str_date); 43 | 44 | // Same as above. 45 | explicit Date(const std::string& str_date); 46 | 47 | // Date from integer in the YYYYMMDD format, e.g. Dec. 26, 2011 is 20111226. 48 | explicit Date(unsigned yyyymmdd); 49 | 50 | // Year must be 4-digit, 51 | // month is 1-based, i.e. 1 .. 12, 52 | // day is 1 .. MonthLength() <= 31 53 | Date(unsigned year, unsigned month, unsigned day); 54 | 55 | // Returns true if the date is not empty, 56 | // as is the case when it is created by the default constructor. 57 | // Most operations on invalid date are not allowed 58 | // (will call error handler). 59 | bool IsValid() const { return date_!=0; } 60 | 61 | // Returns date in YYYYMMDD format, e.g. Dec. 26, 2011 is 20111226. 62 | unsigned AsYYYYMMDD() const; 63 | 64 | // 4-digit year. 65 | unsigned Year() const; 66 | 67 | enum { JAN=1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC }; 68 | // Returns month number JAN .. DEC, i.e. 1..12. 69 | unsigned Month() const; 70 | 71 | // Day of month 1 .. MonthLength() <= 31. 72 | unsigned DayOfMonth() const; 73 | 74 | static bool IsLeap(unsigned year); 75 | 76 | typedef enum { SUN, MON, TUE, WED, THU, FRI, SAT } DayOfWeekType; 77 | // Returns day of week SUN .. SAT. 78 | DayOfWeekType DayOfWeek() const; 79 | 80 | // "Sunday", "Monday" .. "Saturday". 81 | const char* DayOfWeekStr() const; 82 | 83 | int Data() const { return date_; } 84 | 85 | typedef enum { FRMT_AMERICAN, // MM/DD/YYYY 86 | FRMT_EUROPEAN // MM.DD.YYYY 87 | // one can add formats in here if necessary. 88 | } DateOutputFormat; 89 | 90 | enum { MIN_BUFFER_SIZE=11 }; 91 | // The function prints a date into a user-provided buffer 92 | // and returns the same buffer. 93 | // Make sure the buffer size >= MIN_BUFFER_SIZE chars at least. 94 | char* AsString(char* buffer, unsigned bufLen, 95 | DateOutputFormat frmt=FRMT_AMERICAN) const; 96 | 97 | // Same as above, but C++ style. 98 | std::string AsString(DateOutputFormat frmt=FRMT_AMERICAN) const; 99 | 100 | // Returns negative int, 0 or positive int in cases of *thisd. 101 | int CompareTo(const Date& d) const { 102 | SCPP_TEST_ASSERT(IsValid(), "Date is not valid") 103 | SCPP_TEST_ASSERT(d.IsValid(), "Date is not valid") 104 | 105 | return date_ - d.date_; 106 | } 107 | 108 | SCPP_DEFINE_COMPARISON_OPERATORS(Date) 109 | 110 | Date& operator ++ () { 111 | ++date_; 112 | SyncDebug(); 113 | return *this; 114 | } 115 | 116 | Date operator ++ (int) { 117 | Date copy(*this); 118 | ++(*this); 119 | return copy; 120 | } 121 | 122 | Date& operator -- () { 123 | --date_; 124 | SyncDebug(); 125 | return *this; 126 | } 127 | 128 | Date operator -- (int) { 129 | Date copy(*this); 130 | --(*this); 131 | return copy; 132 | } 133 | 134 | Date& operator += (int nDays) { 135 | date_ += nDays; 136 | SyncDebug(); 137 | return *this; 138 | } 139 | 140 | Date& operator -= (int nDays) { 141 | (*this) += (-nDays); 142 | return *this; 143 | } 144 | 145 | private: 146 | int date_; // number of days from A.D., i.e. 01/01/0001 is 1. 147 | 148 | #ifdef _DEBUG 149 | int yyyymmdd_; 150 | #endif 151 | 152 | void SyncDebug() { 153 | #ifdef _DEBUG 154 | yyyymmdd_ = AsYYYYMMDD(); 155 | #endif 156 | } 157 | 158 | void SyncDebug(unsigned year, unsigned month, unsigned day) { 159 | #ifdef _DEBUG 160 | yyyymmdd_ = 10000*year + 100*month + day; 161 | #endif 162 | } 163 | 164 | // Returns month's length in days, 165 | // input: month = 1 .. 12 166 | static unsigned MonthLength(unsigned month, unsigned year); 167 | 168 | // Returns number of calendar days before beginning of the month, 169 | // e.g. for JAN - 0, 170 | // for FEB - 31, 171 | // for MAR - 59 or 60 depending on the leap year. 172 | static unsigned NumberOfDaysBeforeMonth(unsigned month, unsigned year); 173 | }; 174 | } // namespace scpp 175 | 176 | inline std::ostream& operator<<(std::ostream& os, const scpp::Date& d) { 177 | char buffer[scpp::Date::MIN_BUFFER_SIZE]; 178 | os << d.AsString(buffer, scpp::Date::MIN_BUFFER_SIZE); 179 | return os; 180 | } 181 | 182 | inline scpp::Date operator + (const scpp::Date& d, int nDays) { 183 | scpp::Date copy(d); 184 | return (copy += nDays); 185 | } 186 | 187 | inline scpp::Date operator - (const scpp::Date& d, int nDays) { 188 | scpp::Date copy(d); 189 | return (copy -= nDays); 190 | } 191 | 192 | inline int operator - (const scpp::Date& lhs, const scpp::Date& rhs) { 193 | return lhs.Data() - rhs.Data(); 194 | } 195 | #endif // __SCPP_DATE_HPP_INCLUDED__ 196 | -------------------------------------------------------------------------------- /scpp_matrix.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladimir-kushnir/SafeCPlusPlus/f5f161808d638a90e6a3919f8d91b4e0048c7f07/scpp_matrix.hpp -------------------------------------------------------------------------------- /scpp_ptr.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladimir-kushnir/SafeCPlusPlus/f5f161808d638a90e6a3919f8d91b4e0048c7f07/scpp_ptr.hpp -------------------------------------------------------------------------------- /scpp_refcountptr.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladimir-kushnir/SafeCPlusPlus/f5f161808d638a90e6a3919f8d91b4e0048c7f07/scpp_refcountptr.hpp -------------------------------------------------------------------------------- /scpp_scopedptr.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladimir-kushnir/SafeCPlusPlus/f5f161808d638a90e6a3919f8d91b4e0048c7f07/scpp_scopedptr.hpp -------------------------------------------------------------------------------- /scpp_types.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladimir-kushnir/SafeCPlusPlus/f5f161808d638a90e6a3919f8d91b4e0048c7f07/scpp_types.hpp -------------------------------------------------------------------------------- /scpp_vector.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladimir-kushnir/SafeCPlusPlus/f5f161808d638a90e6a3919f8d91b4e0048c7f07/scpp_vector.hpp --------------------------------------------------------------------------------