http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/jsoncpp/json_writer.cpp ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/jsoncpp/json_writer.cpp b/rocketmq-client4cpp/src/jsoncpp/json_writer.cpp new file mode 100755 index 0000000..9d9e0cc --- /dev/null +++ b/rocketmq-client4cpp/src/jsoncpp/json_writer.cpp @@ -0,0 +1,1220 @@ +// Copyright 2011 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include <json/writer.h> +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include <iomanip> +#include <memory> +#include <sstream> +#include <utility> +#include <set> +#include <cassert> +#include <cstring> +#include <cstdio> + +#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 +#include <float.h> +#define isfinite _finite +#elif defined(__sun) && defined(__SVR4) //Solaris +#if !defined(isfinite) +#include <ieeefp.h> +#define isfinite finite +#endif +#elif defined(_AIX) +#if !defined(isfinite) +#include <math.h> +#define isfinite finite +#endif +#elif defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ + _Isfinitef(x) : _IsFinite(x))) +#else +#include <math.h> +#define isfinite finite +#endif +#endif +#else +#include <cmath> +#if !(defined(__QNXNTO__)) // QNX already defines isfinite +#define isfinite std::isfinite +#endif +#endif + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +#define snprintf std::snprintf +#endif +#endif + +#if defined(__BORLANDC__) +#include <float.h> +#define isfinite _finite +#define snprintf _snprintf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace rmq { +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr<StreamWriter> StreamWriterPtr; +#else +typedef std::auto_ptr<StreamWriter> StreamWriterPtr; +#endif + +static bool containsControlCharacter(const char* str) { + while (*str) { + if (isControlCharacter(*(str++))) + return true; + } + return false; +} + +static bool containsControlCharacter0(const char* str, unsigned len) { + char const* end = str + len; + while (end != str) { + if (isControlCharacter(*str) || 0==*str) + return true; + ++str; + } + return false; +} + +JSONCPP_STRING valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +JSONCPP_STRING valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +JSONCPP_STRING valueToString(Int value) { + return valueToString(LargestInt(value)); +} + +JSONCPP_STRING valueToString(UInt value) { + return valueToString(LargestUInt(value)); +} + +#endif // # if defined(JSON_HAS_INT64) + +namespace { +JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) { + // Allocate a buffer that is more than large enough to store the 16 digits of + // precision requested below. + char buffer[32]; + int len = -1; + + char formatString[10]; + snprintf(formatString, sizeof(formatString), "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. + if (isfinite(value)) { + len = snprintf(buffer, sizeof(buffer), formatString, value); + } else { + // IEEE standard states that NaN values will not compare to themselves + if (value != value) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); + } else if (value < 0) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); + } else { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); + } + // For those, we do not need to call fixNumLoc, but it is fast. + } + assert(len >= 0); + fixNumericLocale(buffer, buffer + len); + return buffer; +} +} + +JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } + +JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } + +JSONCPP_STRING valueToQuotedString(const char* value) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && + !containsControlCharacter(value)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + strlen(value) * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c = value; *c != 0; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something. + // blep notes: actually escaping \/ may be useful in javascript to avoid </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: + if (isControlCharacter(*c)) { + JSONCPP_OSTRINGSTREAM oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') + << std::setw(4) << static_cast<int>(*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp +static char const* strnpbrk(char const* s, char const* accept, size_t n) { + assert((s || !n) && accept); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + int const c = *cur; + for (char const* a = accept; *a; ++a) { + if (*a == c) { + return cur; + } + } + } + return NULL; +} +static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && + !containsControlCharacter0(value, length)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + length * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something.) + // blep notes: actually escaping \/ may be useful in javascript to avoid </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: + if ((isControlCharacter(*c)) || (*c == 0)) { + JSONCPP_OSTRINGSTREAM oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') + << std::setw(4) << static_cast<int>(*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() {} + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), + omitEndingLineFeed_(false) {} + +void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } + +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +JSONCPP_STRING FastWriter::write(const Value& root) { + document_ = ""; + writeValue(root); + if (!omitEndingLineFeed_) + document_ += "\n"; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + if (!dropNullPlaceholders_) + document_ += "null"; + break; + case intValue: + document_ += valueToString(value.asLargestInt()); + break; + case uintValue: + document_ += valueToString(value.asLargestUInt()); + break; + case realValue: + document_ += valueToString(value.asDouble()); + break; + case stringValue: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + ArrayIndex size = value.size(); + for (ArrayIndex index = 0; index < size; ++index) { + if (index > 0) + document_ += ','; + writeValue(value[index]); + } + document_ += ']'; + } break; + case objectValue: { + Value::Members members(value.getMemberNames()); + document_ += '{'; + for (Value::Members::iterator it = members.begin(); it != members.end(); + ++it) { + const JSONCPP_STRING& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())); + document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_(74), indentSize_(3), addChildValues_() {} + +JSONCPP_STRING StyledWriter::write(const Value& root) { + document_ = ""; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + document_ += "\n"; + return document_; +} + +void StyledWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const JSONCPP_STRING& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + document_ += " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + writeIndent(); + writeValue(childValue); + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + document_ += "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + +bool StyledWriter::isMultineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + document_ += value; +} + +void StyledWriter::writeIndent() { + if (!document_.empty()) { + char last = document_[document_.length() - 1]; + if (last == ' ') // already indented + return; + if (last != '\n') // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + +void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } + +void StyledWriter::unindent() { + assert(indentString_.size() >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += "\n"; + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += "\n"; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += "\n"; + document_ += root.getComment(commentAfter); + document_ += "\n"; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_() {} + +void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + +void StyledStreamWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + { + // Is NULL possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const JSONCPP_STRING& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + *document_ << " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledStreamWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *document_ << "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + +bool StyledStreamWriter::isMultineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { + if (!indented_) writeIndent(); + *document_ << value; + indented_ = false; +} + +void StyledStreamWriter::indent() { indentString_ += indentation_; } + +void StyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter +{ + BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultineArray(Value const& value); + void pushValue(JSONCPP_STRING const& value); + void writeIndent(); + void writeWithIndent(JSONCPP_STRING const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector<JSONCPP_STRING> ChildValues; + + ChildValues childValues_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + CommentStyle::Enum cs_; + JSONCPP_STRING colonSymbol_; + JSONCPP_STRING nullSymbol_; + JSONCPP_STRING endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) + : rightMargin_(74) + , indentation_(indentation) + , cs_(cs) + , colonSymbol_(colonSymbol) + , nullSymbol_(nullSymbol) + , endingLineFeedSymbol_(endingLineFeedSymbol) + , addChildValues_(false) + , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) +{ +} +int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) +{ + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_ = ""; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = NULL; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); + break; + case stringValue: + { + // Is NULL is possible for value.string_? No. + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + JSONCPP_STRING const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ((!indentation_.empty()) ? ", " : ","); + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast<ArrayIndex>(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { + if (!indented_) writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() + : sout_(NULL) +{ +} +StreamWriter::~StreamWriter() +{ +} +StreamWriter::Factory::~Factory() +{} +StreamWriterBuilder::StreamWriterBuilder() +{ + setDefaults(&settings_); +} +StreamWriterBuilder::~StreamWriterBuilder() +{} +StreamWriter* StreamWriterBuilder::newStreamWriter() const +{ + JSONCPP_STRING indentation = settings_["indentation"].asString(); + JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + JSONCPP_STRING colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + JSONCPP_STRING nullSymbol = "null"; + if (dnp) { + nullSymbol = ""; + } + if (pre > 17) pre = 17; + JSONCPP_STRING endingLineFeedSymbol = ""; + return new BuiltStyledStreamWriter( + indentation, cs, + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); +} +static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); +} +bool StreamWriterBuilder::validate(Value* invalid) const +{ + Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Value& inv = *invalid; + std::set<JSONCPP_STRING> valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) +{ + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Value* settings) +{ + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + //! [StreamWriterBuilderDefaults] +} + +JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { + JSONCPP_OSTRINGSTREAM sout; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json +} // namespace rmq
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/jsoncpp/version ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/jsoncpp/version b/rocketmq-client4cpp/src/jsoncpp/version new file mode 100755 index 0000000..73c8b4f --- /dev/null +++ b/rocketmq-client4cpp/src/jsoncpp/version @@ -0,0 +1 @@ +1.7.7 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/AtomicValue.cpp ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/AtomicValue.cpp b/rocketmq-client4cpp/src/kpr/AtomicValue.cpp new file mode 100755 index 0000000..30777f9 --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/AtomicValue.cpp @@ -0,0 +1,146 @@ +/** + * Copyright (C) 2013 kangliqiang ,[email protected] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "AtomicValue.h" + +#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) + +#include "Mutex.h" + +namespace kpr +{ +static const size_t kSwapLockCount = 64; +static Mutex s_swapLocks[kSwapLockCount]; + +static inline Mutex& getSwapLock(const volatile int64_t* addr) +{ + return s_swapLocks[(reinterpret_cast<intptr_t>(addr) >> 3U) % kSwapLockCount]; +} + +static int64_t atomicAddAndFetch(int64_t volatile* ptr, int64_t step) +{ + Mutex& mutex = getSwapLock(ptr); + + mutex.Lock(); + int64_t value = *ptr + step; + *ptr = value; + mutex.Unlock(); + + return value; +} + +static int64_t atomicFetchAndAdd(int64_t volatile* ptr, int64_t step) +{ + Mutex& mutex = getSwapLock(ptr); + + mutex.Lock(); + int64_t value = *ptr; + *ptr += step; + mutex.Unlock(); + + return value; +} + +static bool atomicBoolCompareAndSwap(int64_t volatile* ptr, int64_t oldval, int64_t newval) +{ + Mutex& mutex = getSwapLock(ptr); + + mutex.Lock(); + if (*ptr == oldval) + { + *ptr = newval; + mutex.Unlock(); + return true; + } + + mutex.Unlock(); + return false; +} + +static int64_t atomicValCompareAndSwap(int64_t volatile* ptr, int64_t oldval, int64_t newval) +{ + Mutex& mutex = getSwapLock(ptr); + + mutex.Lock(); + int64_t value = *ptr; + if (value == oldval) + { + *ptr = newval; + mutex.Unlock(); + return value; + } + + mutex.Unlock(); + return value; +} + + +static int64_t atomicTestAndSet(int64_t volatile* ptr, int64_t val) +{ + Mutex& mutex = getSwapLock(ptr); + + mutex.Lock(); + int64_t value = *ptr; + *ptr = val; + mutex.Unlock(); + + return value; +} + + + +extern "C" { +int64_t __sync_add_and_fetch_8(int64_t volatile* ptr, int64_t value) +{ + return atomicAddAndFetch(ptr, value); +} + +int64_t __sync_sub_and_fetch_8(int64_t volatile* ptr, int64_t value) +{ + return atomicAddAndFetch(ptr, -value); +} + +int64_t __sync_fetch_and_add_8(int64_t volatile* ptr, int64_t value) +{ + return atomicFetchAndAdd(ptr, -value); +} + +int64_t __sync_fetch_and_sub_8(int64_t volatile* ptr, int64_t value) +{ + return atomicFetchAndAdd(ptr, -value); +} + +bool __sync_bool_compare_and_swap_8(volatile int64_t* ptr, int64_t oldval, int64_t newval) +{ + return atomicBoolCompareAndSwap(ptr, oldval, newval); +} + +int64_t __sync_val_compare_and_swap_8(volatile int64_t* ptr, int64_t oldval, int64_t newval) +{ + return atomicValCompareAndSwap(ptr, oldval, newval); +} + +bool __sync_lock_test_and_set_8(int64_t volatile* ptr, int64_t value) +{ + return atomicTestAndSet(ptr, value); +} + + +} // extern "C" + +} // namespace kpr +#endif + + http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/AtomicValue.h ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/AtomicValue.h b/rocketmq-client4cpp/src/kpr/AtomicValue.h new file mode 100755 index 0000000..50d198e --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/AtomicValue.h @@ -0,0 +1,200 @@ +/** + * Copyright (C) 2013 kangliqiang ,[email protected] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __KPR_ATOMICVALUE_H__ +#define __KPR_ATOMICVALUE_H__ + +#include "KPRTypes.h" + +namespace kpr +{ + +template <class T> +class AtomicValue +{ +public: + AtomicValue() + : value(0) + { + } + + AtomicValue(T init) + : value(init) + { + } + + AtomicValue<T>& operator=(T newValue) + { + set(newValue); + return *this; + } + + AtomicValue<T>& operator=(const AtomicValue<T>& v) + { + set(v.get()); + + return *this; + } + + inline T operator+=(T n) + { + return __sync_add_and_fetch(&value, n); + } + + inline T operator-=(T n) + { + return __sync_sub_and_fetch(&value, n); + } + + inline T operator++() + { + return *this += 1; + } + + inline T operator--() + { + return *this -= 1; + } + + inline T fetchAndAdd(T n) + { + return __sync_fetch_and_add(&value, n); + } + + inline T fetchAndSub(T n) + { + return __sync_fetch_and_sub(&value, n); + } + + inline T operator++(int) + { + return fetchAndAdd(1); + } + + inline T operator--(int) + { + return fetchAndSub(1); + } + + operator T() const + { + return get(); + } + + T get() const + { + return const_cast<AtomicValue<T>*>(this)->fetchAndAdd(static_cast<T>(0)); + } + + void set(T n) + { + __sync_lock_test_and_set((T*)&value, n); + } + + inline T getAndSet(T comparand, T exchange) + { + return __sync_val_compare_and_swap((T*)&value, comparand, exchange); + } + + inline bool compareAndSet(T comparand, T exchange) + { + return __sync_bool_compare_and_swap((T*)&value, comparand, exchange); + } + +private: + volatile T value; +}; + + +template <class T> +class AtomicReference +{ +public: + AtomicReference() : value(NULL) {} + AtomicReference(T* init) : value(init) {} + + AtomicReference<T>& operator=(T* newValue) + { + set(newValue); + return *this; + } + + AtomicReference<T>& operator=(const AtomicReference<T>& v) + { + set(v.get()); + + return *this; + } + + T* operator->() const + { + return get(); + } + + T& operator*() + { + return *get(); + } + + operator T*() const + { + return get(); + } + + T* get() const + { + if (value == NULL) + { + return NULL; + } + else + { + return (T*)(__sync_fetch_and_add((uintptr_t*)&value, 0)); + } + } + + void set(T* n) + { + if (value == NULL) + { + value = n; + } + else + { + __sync_lock_test_and_set((uintptr_t*)&value, n); + } + } + + inline T getAndSet(T* comparand, T* exchange) + { + return __sync_val_compare_and_swap((uintptr_t*)&value, comparand, exchange); + } + + inline bool compareAndSet(T* comparand, T* exchange) + { + return __sync_bool_compare_and_swap((uintptr_t*)&value, comparand, exchange); + } + +private: + volatile T* value; +}; + + +typedef AtomicValue<bool> AtomicBoolean; +typedef AtomicValue<int> AtomicInteger; +typedef AtomicValue<long long> AtomicLong; + +} +#endif http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/Condition.cpp ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/Condition.cpp b/rocketmq-client4cpp/src/kpr/Condition.cpp new file mode 100755 index 0000000..c81765e --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/Condition.cpp @@ -0,0 +1,158 @@ +/** + * Copyright (C) 2013 kangliqiang ,[email protected] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "Condition.h" + +#include <errno.h> +#include <assert.h> + +#include "Mutex.h" +#include "ScopedLock.h" +#include "Semaphore.h" +#include "KPRUtil.h" +#include "Exception.h" + +namespace kpr +{ +class ConditionHelper +{ + RecursiveMutex& m_mutex; + int m_count; + +public: + + ConditionHelper(RecursiveMutex& mutex, int count) + : m_mutex(mutex), + m_count(count) + { + } + + ~ConditionHelper() + { + pthread_mutex_unlock(&m_mutex.m_mutex); + m_mutex.lock(m_count); + } +}; + + +Condition::Condition() +{ + pthread_cond_init(&m_cond, 0); +} + +Condition::~Condition() +{ + pthread_cond_destroy(&m_cond); +} + +void Condition::Wait(Mutex& mutex) +{ + wait(mutex, -1); +} + +bool Condition::Wait(Mutex& mutex, long timeout) +{ + assert(timeout >= 0 && "timeout value is negative"); + + return wait(mutex, timeout); +} + +void Condition::Wait(RecursiveMutex& mutex) +{ + wait(mutex, -1); +} + +bool Condition::Wait(RecursiveMutex& mutex, long timeout) +{ + assert(timeout >= 0 && "timeout value is negative"); + + return wait(mutex, timeout); +} + +void Condition::Notify() +{ + pthread_cond_signal(&m_cond); +} + +void Condition::NotifyAll() +{ + pthread_cond_broadcast(&m_cond); +} + +bool Condition::wait(Mutex& mutex, long timeout) +{ + int ret = 0; + if (timeout < 0) + { + ret = pthread_cond_wait(&m_cond, &mutex.m_mutex); + } + else + { + struct timespec abstime = KPRUtil::CalcAbsTime(timeout); + ret = pthread_cond_timedwait(&m_cond, &mutex.m_mutex, &abstime); + } + if (ret == 0) + { + return true; + } + else + { + if (errno == EINTR) + { + THROW_EXCEPTION(InterruptedException, "pthread_cond_timedwait failed", errno); + } + else if (errno == ETIMEDOUT && timeout >= 0) + { + return false; + } + } + return true; +} + +bool Condition::wait(RecursiveMutex& mutex, long timeout) +{ + unsigned int count = mutex.reset4Condvar(); + ConditionHelper unlock(mutex, count); + + int ret = 0; + if (timeout < 0) + { + ret = pthread_cond_wait(&m_cond, &mutex.m_mutex); + } + else + { + struct timespec abstime = KPRUtil::CalcAbsTime(timeout); + ret = pthread_cond_timedwait(&m_cond, &mutex.m_mutex, &abstime); + } + + if (ret == 0) + { + return true; + } + else + { + if (errno == EINTR) + { + THROW_EXCEPTION(InterruptedException, "pthread_cond_timedwait failed", errno); + } + else if (errno == ETIMEDOUT && timeout >= 0) + { + return false; + } + } + + return true; +} +} http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/Condition.h ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/Condition.h b/rocketmq-client4cpp/src/kpr/Condition.h new file mode 100755 index 0000000..901e66c --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/Condition.h @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2013 kangliqiang ,[email protected] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __KPR_CONDITION_H__ +#define __KPR_CONDITION_H__ + +#include "KPRTypes.h" + +namespace kpr +{ +class Mutex; +class RWMutex; +class RecursiveMutex; + +class Condition +{ +public: + Condition(); + ~Condition(); + void Wait(Mutex& mutex); + + bool Wait(Mutex& mutex, long timeout); + + void Wait(RecursiveMutex& mutex); + + bool Wait(RecursiveMutex& mutex, long timeout); + + void Notify(); + + void NotifyAll(); + +private: + bool wait(Mutex&, long timeout); + bool wait(RecursiveMutex&, long timeout); + + Condition(const Condition&); + void operator=(const Condition&); + + pthread_cond_t m_cond; +}; +} +#endif http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/Epoller.cpp ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/Epoller.cpp b/rocketmq-client4cpp/src/kpr/Epoller.cpp new file mode 100755 index 0000000..3c4ddf3 --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/Epoller.cpp @@ -0,0 +1,96 @@ +/** +* Copyright (C) 2013 suwenkuang ,[email protected] +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "Epoller.h" +#include <unistd.h> + +namespace kpr +{ +Epoller::Epoller(bool bEt) +{ + _iEpollfd = -1; + _pevs = NULL; + _et = bEt; + _max_connections = 1024; +} + +Epoller::~Epoller() +{ + if (_pevs != NULL) + { + delete[] _pevs; + _pevs = NULL; + } + + if (_iEpollfd > 0) + { + close(_iEpollfd); + } +} + +void Epoller::ctrl(int fd, long long data, __uint32_t events, int op) +{ + struct epoll_event ev; + ev.data.u64 = data; + if (_et) + { + ev.events = events | EPOLLET; + } + else + { + ev.events = events; + } + + epoll_ctl(_iEpollfd, op, fd, &ev); +} + +void Epoller::create(int max_connections) +{ + _max_connections = max_connections; + + _iEpollfd = epoll_create(_max_connections + 1); + + if (_pevs != NULL) + { + delete[] _pevs; + } + + _pevs = new epoll_event[_max_connections + 1]; +} + +void Epoller::add(int fd, long long data, __uint32_t event) +{ + ctrl(fd, data, event, EPOLL_CTL_ADD); +} + +void Epoller::mod(int fd, long long data, __uint32_t event) +{ + ctrl(fd, data, event, EPOLL_CTL_MOD); +} + +void Epoller::del(int fd, long long data, __uint32_t event) +{ + ctrl(fd, data, event, EPOLL_CTL_DEL); +} + +int Epoller::wait(int millsecond) +{ + return epoll_wait(_iEpollfd, _pevs, _max_connections + 1, millsecond); +} + +} + + http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/Epoller.h ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/Epoller.h b/rocketmq-client4cpp/src/kpr/Epoller.h new file mode 100755 index 0000000..d3d161b --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/Epoller.h @@ -0,0 +1,62 @@ +/** +* Copyright (C) 2013 suwenkuang ,[email protected] +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __KPR_EPOLLER_H_ +#define __KPR_EPOLLER_H_ + +#include <unistd.h> +#include <sys/epoll.h> +#include <cassert> + +namespace kpr +{ + + +class Epoller +{ +public: + Epoller(bool bEt = true); + ~Epoller(); + + + void create(int max_connections); + + void add(int fd, long long data, __uint32_t event); + void mod(int fd, long long data, __uint32_t event); + void del(int fd, long long data, __uint32_t event); + + int wait(int millsecond); + + struct epoll_event& get(int i) + { + assert(_pevs != 0); + return _pevs[i]; + } + +protected: + void ctrl(int fd, long long data, __uint32_t events, int op); + +protected: + int _iEpollfd; + int _max_connections; + struct epoll_event* _pevs; + bool _et; +}; + +} +#endif + + http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/Exception.h ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/Exception.h b/rocketmq-client4cpp/src/kpr/Exception.h new file mode 100755 index 0000000..524af84 --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/Exception.h @@ -0,0 +1,100 @@ +/** + * Copyright (C) 2013 kangliqiang ,[email protected] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __KPR_EXCEPTION_H +#define __KPR_EXCEPTION_H + +#include "KPRTypes.h" +#include <exception> +#include <string> +#include <sstream> + +namespace kpr +{ +class Exception : public std::exception +{ +public: + Exception(const char* msg, int error, const char* file, int line)throw() + : m_error(error), m_line(line), m_msg(msg), m_file(file) + { + try + { + std::stringstream ss; + ss << "[" << file << ":" << line << "]|error: " << error << "|msg:" << msg; + m_msg = ss.str(); + } + catch (...) + { + } + } + + virtual ~Exception()throw() + { + } + + const char* what() const throw() + { + return m_msg.c_str(); + } + + int GetError() const throw() + { + return m_error; + } + + virtual const char* GetType() const throw() + { + return "Exception"; + } + +protected: + int m_error; + int m_line; + std::string m_msg; + std::string m_file; +}; +} + +inline std::ostream& operator<<(std::ostream& os, const kpr::Exception& e) +{ + os << "Type:" << e.GetType() << e.what(); + return os; +} + +#define DEFINE_EXCEPTION(name) \ + class name : public kpr::Exception \ + {\ + public:\ + name(const char* msg, int error,const char* file,int line) throw ()\ + : Exception(msg,error,file,line) {}\ + virtual const char* GetType() const throw()\ + {\ + return #name;\ + }\ + }; + +namespace kpr +{ +DEFINE_EXCEPTION(SystemCallException); +DEFINE_EXCEPTION(NotImplementException); +DEFINE_EXCEPTION(InterruptedException); +DEFINE_EXCEPTION(FileUtilException); +DEFINE_EXCEPTION(RefHandleNullException); + +}; + +#define THROW_EXCEPTION(e,msg,err) throw e(msg,err,__FILE__,__LINE__); + +#endif http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/FileUtil.cpp ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/FileUtil.cpp b/rocketmq-client4cpp/src/kpr/FileUtil.cpp new file mode 100755 index 0000000..aa239e4 --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/FileUtil.cpp @@ -0,0 +1,523 @@ +/** +* Copyright (C) 2013 suwenkuang ,[email protected] +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <string.h> +#include <time.h> +#include <errno.h> +#include <unistd.h> +#include <stdint.h> +#include <stdlib.h> +#include <fcntl.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <cassert> +#include <cstdio> +#include <string> +#include <iostream> +#include <sstream> +#include <stdexcept> +#include <algorithm> +#include <map> +#include <stack> +#include <vector> + +#include "FileUtil.h" +#include "KPRUtil.h" +#include "Exception.h" + + +namespace kpr +{ + +std::ifstream::pos_type FileUtil::getFileSize(const std::string& sFullFileName) +{ + std::ifstream ifs(sFullFileName.c_str()); + ifs.seekg(0, std::ios_base::end); + return ifs.tellg(); +} + +bool FileUtil::isAbsolute(const std::string& sFullFileName) +{ + if (sFullFileName.empty()) + { + return false; + } + + unsigned i = 0; + while (isspace(sFullFileName[i])) + { + ++i; + } + + return sFullFileName[i] == '/'; +} + +bool FileUtil::isFileExist(const std::string& sFullFileName, mode_t iFileType) +{ + struct stat f_stat; + + if (lstat(sFullFileName.c_str(), &f_stat) == -1) + { + return false; + } + + if (!(f_stat.st_mode & iFileType)) + { + return false; + } + + return true; +} + +bool FileUtil::isFileExistEx(const std::string& sFullFileName, mode_t iFileType) +{ + struct stat f_stat; + + if (stat(sFullFileName.c_str(), &f_stat) == -1) + { + return false; + } + + if (!(f_stat.st_mode & iFileType)) + { + return false; + } + + return true; +} + +bool FileUtil::makeDir(const std::string& sDirectoryPath, mode_t iFlag) +{ + int iRetCode = mkdir(sDirectoryPath.c_str(), iFlag); + if (iRetCode < 0 && errno == EEXIST) + { + return isFileExistEx(sDirectoryPath, S_IFDIR); + } + + return iRetCode == 0; +} + +bool FileUtil::makeDirRecursive(const std::string& sDirectoryPath, mode_t iFlag) +{ + std::string simple = simplifyDirectory(sDirectoryPath); + + std::string::size_type pos = 0; + for (; pos != std::string::npos;) + { + pos = simple.find("/", pos + 1); + std::string s; + if (pos == std::string::npos) + { + s = simple.substr(0, simple.size()); + return makeDir(s.c_str(), iFlag); + } + else + { + s = simple.substr(0, pos); + if (!makeDir(s.c_str(), iFlag)) + { + return false; + } + } + } + return true; +} + +int FileUtil::setExecutable(const std::string& sFullFileName, bool canExecutable) +{ + struct stat f_stat; + + if (stat(sFullFileName.c_str(), &f_stat) == -1) + { + return -1; + } + + return chmod(sFullFileName.c_str(), canExecutable ? f_stat.st_mode | S_IXUSR : f_stat.st_mode & ~S_IXUSR); +} + +bool FileUtil::canExecutable(const std::string& sFullFileName) +{ + struct stat f_stat; + + if (stat(sFullFileName.c_str(), &f_stat) == -1) + { + return false; + } + + return f_stat.st_mode & S_IXUSR; +} + +int FileUtil::removeFile(const std::string& sFullFileName, bool bRecursive) +{ + std::string path = simplifyDirectory(sFullFileName); + + if (isFileExist(path, S_IFDIR)) + { + if (bRecursive) + { + std::vector<std::string> files; + listDirectory(path, files, false); + for (size_t i = 0; i < files.size(); i++) + { + removeFile(files[i], bRecursive); + } + + if (path != "/") + { + if (::rmdir(path.c_str()) == -1) + { + return -1; + } + return 0; + } + } + else + { + if (::rmdir(path.c_str()) == -1) + { + return -1; + } + } + } + else + { + if (::remove(path.c_str()) == -1) + { + return -1; + } + } + + return 0; +} + +std::string FileUtil::simplifyDirectory(const std::string& path) +{ + std::string result = path; + + std::string::size_type pos; + + pos = 0; + while ((pos = result.find("//", pos)) != std::string::npos) + { + result.erase(pos, 1); + } + + pos = 0; + while ((pos = result.find("/./", pos)) != std::string::npos) + { + result.erase(pos, 2); + } + + while (result.substr(0, 4) == "/../") + { + result.erase(0, 3); + } + + if (result == "/.") + { + return result.substr(0, result.size() - 1); + } + + if (result.size() >= 2 && result.substr(result.size() - 2, 2) == "/.") + { + result.erase(result.size() - 2, 2); + } + + if (result == "/") + { + return result; + } + + if (result.size() >= 1 && result[result.size() - 1] == '/') + { + result.erase(result.size() - 1); + } + + if (result == "/..") + { + result = "/"; + } + + return result; +} + +std::string FileUtil::load2str(const std::string& sFullFileName) +{ + std::ifstream ifs(sFullFileName.c_str()); + if (!ifs) + { + return ""; + } + return std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>()); +} + +void FileUtil::save2file(const std::string& sFullFileName, const std::string& sFileData) +{ + std::ofstream ofs((sFullFileName).c_str()); + ofs << sFileData; + ofs.close(); +} + +int FileUtil::save2file(const std::string& sFullFileName, const char* sFileData, size_t length) +{ + FILE* fp = fopen(sFullFileName.c_str(), "wb"); + if (fp == NULL) + { + return -1; + } + + size_t ret = fwrite((void*)sFileData, 1, length, fp); + fclose(fp); + + if (ret == length) + { + return 0; + } + return -1; +} + +std::string FileUtil::getExePath() +{ + std::string proc = "/proc/self/exe"; + char buf[2048] = "\0"; + + int bufsize = sizeof(buf) / sizeof(char); + + int count = readlink(proc.c_str(), buf, bufsize); + + if (count < 0) + { + THROW_EXCEPTION(FileUtilException, "could not get exe path error", errno); + } + + count = (count >= bufsize) ? (bufsize - 1) : count; + + buf[count] = '\0'; + return buf; +} + +std::string FileUtil::extractFileName(const std::string& sFullFileName) +{ + if (sFullFileName.length() <= 0) + { + return ""; + } + + std::string::size_type pos = sFullFileName.rfind('/'); + if (pos == std::string::npos) + { + return sFullFileName; + } + + return sFullFileName.substr(pos + 1); +} + +std::string FileUtil::extractFilePath(const std::string& sFullFileName) +{ + if (sFullFileName.length() <= 0) + { + return "./"; + } + + std::string::size_type pos = 0; + + for (pos = sFullFileName.length(); pos != 0 ; --pos) + { + if (sFullFileName[pos - 1] == '/') + { + return sFullFileName.substr(0, pos); + } + } + + return "./"; +} + +std::string FileUtil::extractFileExt(const std::string& sFullFileName) +{ + std::string::size_type pos; + if ((pos = sFullFileName.rfind('.')) == std::string::npos) + { + return std::string(""); + } + + return sFullFileName.substr(pos + 1); +} + +std::string FileUtil::excludeFileExt(const std::string& sFullFileName) +{ + std::string::size_type pos; + if ((pos = sFullFileName.rfind('.')) == std::string::npos) + { + return sFullFileName; + } + + return sFullFileName.substr(0, pos); +} + +std::string FileUtil::replaceFileExt(const std::string& sFullFileName, const std::string& sExt) +{ + return excludeFileExt(sFullFileName) + "." + sExt; +} + +std::string FileUtil::extractUrlFilePath(const std::string& sUrl) +{ + std::string sLowerUrl = KPRUtil::lower(sUrl); + std::string::size_type pos = sLowerUrl.find("http://"); + + if (pos == 0) + { + pos += strlen("http://"); + } + else if (pos == std::string::npos) + { + pos = 0; + } + + for (; pos < sUrl.length(); ++pos) + { + if (sUrl[pos] == '/') + { + if (pos < sUrl.length() - 1) + { + pos++; + break; + } + else + { + return ""; + } + } + } + + if (pos == std::string::npos || pos == sUrl.length()) + { + pos = 0; + } + + return sUrl.substr(pos); +} + +size_t FileUtil::scanDir(const std::string& sFilePath, std::vector<std::string>& vtMatchFiles, FILE_SELECT f, int iMaxSize) +{ + vtMatchFiles.clear(); + + struct dirent** namelist; + int n = scandir(sFilePath.c_str(), &namelist, f, alphasort); + + if (n < 0) + { + return 0; + } + else + { + while (n--) + { + if (iMaxSize > 0 && vtMatchFiles.size() >= (size_t)iMaxSize) + { + free(namelist[n]); + break; + } + else + { + vtMatchFiles.push_back(namelist[n]->d_name); + free(namelist[n]); + } + } + free(namelist); + } + + return vtMatchFiles.size(); +} + +void FileUtil::listDirectory(const std::string& path, std::vector<std::string>& files, bool bRecursive) +{ + std::vector<std::string> tf; + scanDir(path, tf, 0, 0); + + for (size_t i = 0; i < tf.size(); i++) + { + if (tf[i] == "." || tf[i] == "..") + { + continue; + } + + std::string s = path + "/" + tf[i]; + + if (isFileExist(s, S_IFDIR)) + { + files.push_back(simplifyDirectory(s)); + if (bRecursive) + { + listDirectory(s, files, bRecursive); + } + } + else + { + files.push_back(simplifyDirectory(s)); + } + } +} + +void FileUtil::copyFile(const std::string& sExistFile, const std::string& sNewFile, bool bRemove) +{ + if (FileUtil::isFileExist(sExistFile, S_IFDIR)) + { + FileUtil::makeDir(sNewFile); + std::vector<std::string> tf; + FileUtil::scanDir(sExistFile, tf, 0, 0); + for (size_t i = 0; i < tf.size(); i++) + { + if (tf[i] == "." || tf[i] == "..") + { + continue; + } + std::string s = sExistFile + "/" + tf[i]; + std::string d = sNewFile + "/" + tf[i]; + copyFile(s, d, bRemove); + } + } + else + { + if (bRemove) + { + std::remove(sNewFile.c_str()); + } + std::ifstream fin(sExistFile.c_str()); + if (!fin) + { + THROW_EXCEPTION(FileUtilException, "[FileUtil::copyFile] infile open fail", errno); + } + std::ofstream fout(sNewFile.c_str()); + if (!fout) + { + THROW_EXCEPTION(FileUtilException, "[FileUtil::copyFile] newfile open fail", errno); + } + struct stat f_stat; + if (stat(sExistFile.c_str(), &f_stat) == -1) + { + THROW_EXCEPTION(FileUtilException, "[FileUtil::copyFile] infile stat fail", errno); + } + chmod(sNewFile.c_str(), f_stat.st_mode); + fout << fin.rdbuf(); + fin.close(); + fout.close(); + + } +} + +} + http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/FileUtil.h ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/FileUtil.h b/rocketmq-client4cpp/src/kpr/FileUtil.h new file mode 100755 index 0000000..c1e8518 --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/FileUtil.h @@ -0,0 +1,90 @@ +/** +* Copyright (C) 2013 suwenkuang ,[email protected] +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __KPR_FILEUTIL_H_ +#define __KPR_FILEUTIL_H_ + +#include <iostream> +#include <fstream> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <fnmatch.h> + + +#include <string> +#include <vector> + + +namespace kpr +{ + +class FileUtil +{ +public: + + static std::ifstream::pos_type getFileSize(const std::string& sFullFileName); + + static bool isAbsolute(const std::string& sFullFileName); + + static bool isFileExist(const std::string& sFullFileName, mode_t iFileType = S_IFREG); + + static bool isFileExistEx(const std::string& sFullFileName, mode_t iFileType = S_IFREG); + + static std::string simplifyDirectory(const std::string& path); + + static bool makeDir(const std::string& sDirectoryPath, mode_t iFlag = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + + static bool makeDirRecursive(const std::string& sDirectoryPath, mode_t iFlag = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + + static int setExecutable(const std::string& sFullFileName, bool canExecutable); + + static bool canExecutable(const std::string& sFullFileName); + + static int removeFile(const std::string& sFullFileName, bool bRecursive); + + static std::string load2str(const std::string& sFullFileName); + + static void save2file(const std::string& sFullFileName, const std::string& sFileData); + + static int save2file(const std::string& sFullFileName, const char* sFileData, size_t length); + + static std::string getExePath(); + + static std::string extractFileName(const std::string& sFullFileName); + + static std::string extractFilePath(const std::string& sFullFileName); + + static std::string extractFileExt(const std::string& sFullFileName); + + static std::string excludeFileExt(const std::string& sFullFileName); + + static std::string replaceFileExt(const std::string& sFullFileName, const std::string& sExt); + + static std::string extractUrlFilePath(const std::string& sUrl); + + typedef int (*FILE_SELECT)(const dirent*); + + static size_t scanDir(const std::string& sFilePath, std::vector<std::string>& vtMatchFiles, FILE_SELECT f = NULL, int iMaxSize = 0); + + static void listDirectory(const std::string& path, std::vector<std::string>& files, bool bRecursive); + + static void copyFile(const std::string& sExistFile, const std::string& sNewFile, bool bRemove = false); +}; + +} +#endif // __FILE_UTIL_H_ http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/KPRTypes.h ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/KPRTypes.h b/rocketmq-client4cpp/src/kpr/KPRTypes.h new file mode 100755 index 0000000..0a54123 --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/KPRTypes.h @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2013 kangliqiang ,[email protected] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __KPR_TYPES_H__ +#define __KPR_TYPES_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <sys/time.h> +#include <pthread.h> +#include <semaphore.h> + + +typedef pthread_key_t ThreadKey; + + +namespace kpr +{ +class ThreadId +{ +public: + ThreadId(pthread_t id = 0) + : m_threadId(id) + { + } + + bool operator==(const ThreadId& id) const + { + return m_threadId == id.m_threadId; + } + + bool operator!=(const ThreadId& id) const + { + return !(*this == id); + } + + operator pthread_t() const + { + return m_threadId; + } + + static ThreadId GetCurrentThreadId() + { + return ThreadId(pthread_self()); + } + + pthread_t m_threadId; +}; +} + +#endif http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/KPRUtil.cpp ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/KPRUtil.cpp b/rocketmq-client4cpp/src/kpr/KPRUtil.cpp new file mode 100755 index 0000000..fe2cdd2 --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/KPRUtil.cpp @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2013 kangliqiang ,[email protected] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "KPRUtil.h" +#include <assert.h> + + + +unsigned long long KPRUtil::GetCurrentTimeMillis() +{ + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_sec * 1000ULL + tv.tv_usec / 1000; +} + +struct timespec KPRUtil::CalcAbsTime(long timeout) +{ + assert(timeout >= 0); + struct timeval tv; + gettimeofday(&tv, 0); + + struct timespec abstime; + abstime.tv_sec = tv.tv_sec + (timeout / 1000); + abstime.tv_nsec = (tv.tv_usec * 1000) + ((timeout % 1000) * 1000000); + if (abstime.tv_nsec >= 1000000000) + { + ++abstime.tv_sec; + abstime.tv_nsec -= 1000000000; + } + + return abstime; +} + +long long KPRUtil::str2ll(const char* str) +{ + return atoll(str); +} + + +std::string KPRUtil::lower(const std::string& s) +{ + std::string sString = s; + for (std::string::iterator iter = sString.begin(); iter != sString.end(); ++iter) + { + *iter = tolower(*iter); + } + + return sString; +} + +std::string KPRUtil::upper(const std::string& s) +{ + std::string sString = s; + + for (std::string::iterator iter = sString.begin(); iter != sString.end(); ++iter) + { + *iter = toupper(*iter); + } + + return sString; +} + + + http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/KPRUtil.h ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/KPRUtil.h b/rocketmq-client4cpp/src/kpr/KPRUtil.h new file mode 100755 index 0000000..ae2c529 --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/KPRUtil.h @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2013 kangliqiang ,[email protected] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __KPR_UTIL_H__ +#define __KPR_UTIL_H__ + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/time.h> +#include <stdlib.h> +#include <string> + + +class KPRUtil +{ +public: + static struct timespec CalcAbsTime(long timeout); + static unsigned long long GetCurrentTimeMillis(); + static long long str2ll(const char* str); + static std::string lower(const std::string& s); + static std::string upper(const std::string& s); +}; + + +#endif http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/Monitor.cpp ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/Monitor.cpp b/rocketmq-client4cpp/src/kpr/Monitor.cpp new file mode 100644 index 0000000..d715f55 --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/Monitor.cpp @@ -0,0 +1,125 @@ +/** + * Copyright (C) 2013 kangliqiang ,[email protected] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "Monitor.h" +#include <assert.h> + +namespace kpr +{ +Monitor::Monitor() + : m_notifyCount(0) +{ +} + +Monitor::~Monitor() +{ +} + +void Monitor::Wait() +{ + validateOwner(m_mutex.GetOwner(), "wait()"); + + notify(m_notifyCount); + + try + { + m_condition.Wait(m_mutex); + } + catch (...) + { + m_notifyCount = 0; + throw; + } + m_notifyCount = 0; +} + +void Monitor::Wait(long timeout) +{ + validateOwner(m_mutex.GetOwner(), "wait(long)"); + + notify(m_notifyCount); + try + { + m_condition.Wait(m_mutex, timeout); + } + catch (...) + { + m_notifyCount = 0; + throw; + } + + m_notifyCount = 0; +} + +void Monitor::Notify() +{ + validateOwner(m_mutex.GetOwner(), "notify"); + + if (m_notifyCount != -1) + { + ++m_notifyCount; + } +} + +void Monitor::NotifyAll() +{ + validateOwner(m_mutex.GetOwner(), "notifyAll"); + + m_notifyCount = -1; +} + +void Monitor::Lock() const +{ + if (m_mutex.Lock()) + { + m_notifyCount = 0; + } +} + +void Monitor::Unlock() const +{ + if (m_mutex.GetCount() == 1) + { + ((Monitor*)this)->notify(m_notifyCount); + } + + m_mutex.Unlock(); +} + +void Monitor::notify(int nnotify) +{ + if (nnotify != 0) + { + if (nnotify == -1) + { + m_condition.NotifyAll(); + return; + } + else + { + while (nnotify > 0) + { + m_condition.Notify(); + --nnotify; + } + } + } +} + +void Monitor::validateOwner(const ThreadId& id, const char* caller) const +{ + assert(id == ThreadId::GetCurrentThreadId()); +} +} http://git-wip-us.apache.org/repos/asf/incubator-rocketmq-externals/blob/6a45c767/rocketmq-client4cpp/src/kpr/Monitor.h ---------------------------------------------------------------------- diff --git a/rocketmq-client4cpp/src/kpr/Monitor.h b/rocketmq-client4cpp/src/kpr/Monitor.h new file mode 100644 index 0000000..345f736 --- /dev/null +++ b/rocketmq-client4cpp/src/kpr/Monitor.h @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2013 kangliqiang ,[email protected] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __KPR_MONITOR_H__ +#define __KPR_MONITOR_H__ + +#include "KPRTypes.h" +#include "Condition.h" +#include "Mutex.h" +namespace kpr +{ +class Monitor +{ +public: + Monitor(); + virtual ~Monitor(); + + void Wait(); + void Wait(long msec); + + void Notify(); + void NotifyAll(); + + void Lock() const; + void Unlock() const; + +private: + void notify(int times); + void validateOwner(const ThreadId& id, const char* caller) const; + + RecursiveMutex m_mutex; + Condition m_condition; + mutable int m_notifyCount; +}; +} +#endif
