Arquivos
hhvm/hphp/util/json.h
T
Andrei Alexandrescu a2e76eb7b2 Eliminate static noise from .h files
The codebase had several namespace-level static data definitions and function definitions. Using namespace-level "static" in a .h file is near-always a bad idea, as follows:

  - for simple types, static is implied. Example: "const int x = 42;" is the same as "static const int x = 42;"
  - for aggregate types, static linkage implies that a copy of the aggregate will appear in every compilation unit that includes the header.
  - for functions, static means the function will have a separate body generated in each compilation unit including the header.
  - in several places functions were defined 'static inline', which is just as bad. 'inline' is just a hint which means the function may end up having a body (and actually more due to 'static').

True, gnu's linker has means to remove duplicate definition, but that's not always guaranteed or possible (think e.g. static functions that define static data inside, ouch). So static is useless at best and pernicious at worst. We should never, ever use static at namespace level in headers. I will create a bootcamp task for a lint rule.

I expected the performance to be neutral after the change, but in fact there's a significant drop in instruction count and therefore a measurable reduction in CPU time: https://our.intern.facebook.com/intern/perflab/details.php?eq_id=431903
2013-06-06 11:39:13 -07:00

274 linhas
6.4 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_JSON_H_
#define incl_HPHP_JSON_H_
#include "hphp/util/base.h"
namespace HPHP {
DECLARE_BOOST_TYPES(AnalysisResult);
namespace JSON {
///////////////////////////////////////////////////////////////////////////////
template <typename T> class _OutputStream;
template <typename T> class _MapStream;
template <typename T> class _ListStream;
template <typename T> class _ISerializable;
#define DEFINE_JSON_OUTPUT_TYPE(type) \
struct type { \
typedef _OutputStream<type> OutputStream; \
typedef _MapStream<type> MapStream; \
typedef _ListStream<type> ListStream; \
typedef _ISerializable<type> ISerializable; \
}
DEFINE_JSON_OUTPUT_TYPE(CodeError);
DEFINE_JSON_OUTPUT_TYPE(DocTarget);
std::string Escape(const char *s);
template <typename T>
class _ISerializable {
public:
virtual ~_ISerializable() {}
/**
* Generate JSON output of this data structure.
*/
virtual void serialize(_OutputStream<T> &out) const = 0;
};
class Name {
public:
explicit Name(const char *name) {
assert(name && *name);
m_name = name;
}
explicit Name(const std::string &name) {
assert(!name.empty());
m_name = name;
}
const std::string &getName() const { return m_name; }
private:
std::string m_name;
};
// struct _Null {};
// _Null Null;
enum class Null {};
template <typename Type>
class _OutputStream {
public:
_OutputStream(std::ostream &out,
AnalysisResultPtr ar) : m_out(out), m_ar(ar) {}
_OutputStream &operator<< (unsigned int v) { m_out << v; return *this; }
_OutputStream &operator<< (int v) { m_out << v; return *this; }
_OutputStream &operator<< (bool v) {
m_out << (v ? "true" : "false");
return *this;
}
_OutputStream &operator<< (const char *v) {
m_out << "\"" << Escape(v) << "\"";
return *this;
}
_OutputStream &operator<< (const std::string &v) {
m_out << "\"" << Escape(v.c_str()) << "\"";
return *this;
}
_OutputStream &operator<< (const Name &n) {
m_out << "\"" << n.getName() << "\":";
return *this;
}
_OutputStream &operator<< (const Null &n) {
m_out << "null";
return *this;
}
_OutputStream &operator<< (const _ISerializable<Type> &v) {
v.serialize(*this);
return *this;
}
template<typename T>
_OutputStream &operator<< (const boost::shared_ptr<T> &v) {
if (v) {
*this << *v;
} else {
*this << Null();
}
return *this;
}
template<typename T>
_OutputStream &operator<< (const std::vector<T> &v) {
m_out << "[";
for (unsigned int i = 0; i < v.size(); i++) {
if (i > 0) m_out << ',';
*this << v[i];
}
m_out << "]";
return *this;
}
template<typename T>
_OutputStream &operator<< (const std::set<T> &v) {
m_out << "[";
bool first = true;
BOOST_FOREACH(T el, v) {
if (first) {
first = false;
} else {
m_out << ',';
}
*this << el;
}
m_out << "]";
return *this;
}
// TODO: std::map and __gnu_cxx::hash_map should share
// the same function...
template<typename K, typename T, typename C>
_OutputStream &operator<< (const std::map<K, T, C> &v) {
m_out << "{";
for (typename std::map<K, T, C>::const_iterator iter = v.begin();
iter != v.end(); ++iter) {
if (iter != v.begin()) m_out << ',';
*this << Name(iter->first);
*this << iter->second;
}
m_out << "}\n";
return *this;
}
template<typename K, typename T, typename C>
_OutputStream &operator<<
(const hphp_hash_map<K, T, C> &v) {
m_out << "{";
for (typename hphp_hash_map<K, T, C>::const_iterator
iter = v.begin(); iter != v.end(); ++iter) {
if (iter != v.begin()) m_out << ',';
*this << Name(iter->first);
*this << iter->second;
}
m_out << "}\n";
return *this;
}
AnalysisResultPtr analysisResult() const { return m_ar; }
private:
std::ostream &m_out;
AnalysisResultPtr m_ar;
std::ostream &raw() { return m_out;}
friend class _MapStream<Type>;
friend class _ListStream<Type>;
};
template <typename Type>
class _MapStream {
public:
explicit _MapStream(_OutputStream<Type> &jout)
: m_out(jout.raw()), m_jout(jout), m_first(true) {}
template<typename T>
_MapStream &add(const std::string &n, T v) {
init(n);
m_jout << v;
return *this;
}
_MapStream &add(const std::string &n) {
init(n);
return *this;
}
void done() {
if (m_first) {
m_out << "{";
}
m_out << "}\n";
}
private:
std::ostream &m_out;
_OutputStream<Type> &m_jout;
bool m_first;
void init(const std::string &n) {
if (m_first) {
m_out << "{";
m_first = false;
} else {
m_out << ",";
}
m_jout << Name(n);
}
};
template <typename Type>
class _ListStream {
public:
explicit _ListStream(_OutputStream<Type> &jout)
: m_out(jout.raw()), m_jout(jout), m_first(true) {}
void next() {
if (m_first) {
m_out << "[";
m_first = false;
} else {
m_out << ",";
}
}
template<typename T>
_ListStream &operator<< (T &v) {
next();
m_jout << v;
return *this;
}
void done() {
if (m_first) {
m_out << "[";
}
m_out << "]\n";
}
private:
std::ostream &m_out;
_OutputStream<Type> &m_jout;
bool m_first;
};
///////////////////////////////////////////////////////////////////////////////
}}
#endif // incl_HPHP_JSON_H_