Toplevel entrypoints for classes/traits/interfaces
[hiphop-php.git] / hphp / util / hdf.cpp
blob86bcf50da4f5016c88d44d4a2cecad3eaac558d1
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/util/hdf.h"
19 #include <mutex>
21 #include <folly/portability/String.h>
23 #include <boost/algorithm/string/predicate.hpp>
25 namespace HPHP {
26 ///////////////////////////////////////////////////////////////////////////////
28 /**
29 * Helper class storing HDF raw pointer and reference counts on it.
31 struct HdfRaw {
32 static std::mutex HdfMutex;
34 HdfRaw() : m_hdf(nullptr), m_count(1) {
35 // ClearSilver is not thread-safe when calling hdf_init(), so guarding it.
36 std::lock_guard<std::mutex> lock(HdfMutex);
37 Hdf::CheckNeoError(hdf_init(&m_hdf));
38 assert(m_hdf);
40 ~HdfRaw() {
41 if (m_hdf) {
42 hdf_destroy(&m_hdf);
46 HDF *m_hdf;
47 int m_count;
49 void inc() { m_count++;}
50 void dec() { assert(m_count > 0); if (--m_count == 0) { delete this;}}
53 std::mutex HdfRaw::HdfMutex;
55 ///////////////////////////////////////////////////////////////////////////////
56 // constructors
58 Hdf::Hdf() : m_hdf(nullptr), m_dump(nullptr) {
59 m_rawp = new HdfRaw();
62 Hdf::Hdf(const char *filename) : m_hdf(nullptr), m_dump(nullptr) {
63 m_rawp = new HdfRaw();
64 append(filename);
67 Hdf::Hdf(const std::string &filename) : m_hdf(nullptr), m_dump(nullptr) {
68 m_rawp = new HdfRaw();
69 append(filename.c_str());
72 Hdf::Hdf(const Hdf *hdf, const char *name) : m_hdf(nullptr), m_dump(nullptr) {
73 assert(hdf);
74 assert(name && *name);
75 m_rawp = hdf->m_rawp;
76 if (m_rawp) {
77 m_rawp->inc();
78 m_path = hdf->getFullPath();
79 m_name = name;
80 } else {
81 assert(hdf->m_hdf);
82 hdf_get_node(hdf->m_hdf, (char*)name, &m_hdf);
86 Hdf::Hdf(const Hdf &hdf)
87 : m_hdf(hdf.m_hdf), m_rawp(hdf.m_rawp), m_path(hdf.m_path),
88 m_name(hdf.m_name), m_dump(nullptr) {
89 if (m_rawp) {
90 m_rawp->inc();
94 Hdf::Hdf(HDF *hdf)
95 : m_hdf(hdf), m_rawp(nullptr), m_dump(nullptr) {
98 Hdf::~Hdf() {
99 if (m_rawp) {
100 m_rawp->dec();
102 if (m_dump) {
103 free(m_dump);
107 bool Hdf::isEmpty() const {
108 return this->getFullPath() == "" &&
109 this->getName() == "";
112 void Hdf::assign(const Hdf &hdf) {
113 m_hdf = hdf.m_hdf;
114 if (m_rawp) {
115 m_rawp->dec();
117 m_rawp = hdf.m_rawp;
118 if (m_rawp) {
119 m_rawp->inc();
121 m_path = hdf.m_path;
122 m_name = hdf.m_name;
123 if (m_dump) {
124 free(m_dump);
125 m_dump = nullptr;
129 void Hdf::copy(const Hdf &hdf) {
130 CheckNeoError(hdf_copy(getRaw(), nullptr, hdf.getRaw()));
133 void Hdf::open(const char *filename) {
134 close();
135 append(filename);
138 void Hdf::append(const char *filename) {
139 assert(filename && *filename);
140 if (!(boost::contains(filename, ".hdf")
141 || boost::ends_with(filename, ".hphp"))) {
142 return;
144 CheckNeoError(hdf_read_file(getRaw(), (char*)filename));
147 void Hdf::close() {
148 m_hdf = nullptr;
149 if (m_rawp) {
150 m_rawp->dec();
151 m_rawp = new HdfRaw();
153 m_path.clear();
154 m_name.clear();
155 if (m_dump) {
156 free(m_dump);
157 m_dump = nullptr;
161 static bool match(const std::string &name, const std::string &pattern) {
162 assert(!name.empty() && !pattern.empty());
164 unsigned int len = pattern.size();
165 char first = pattern[0];
166 char last = pattern[len - 1];
167 if (first == '*') {
168 if (last == '*') {
169 return name.find(pattern.substr(1, len - 2)) != std::string::npos;
171 return name.size() >= len - 1 &&
172 name.substr(name.size() - len + 1) == pattern.substr(1);
174 if (last == '*') {
175 return strncmp(name.c_str(), pattern.c_str(), len - 1) == 0;
177 return name == pattern;
180 bool Hdf::lintImpl(std::vector<std::string> &names,
181 const std::vector<std::string> &excludes, bool visited) {
182 unsigned int size = names.size();
184 bool childVisited = false;
185 for (Hdf hdf = firstChild(false); hdf.exists(); hdf = hdf.next(false)) {
186 if (hdf.lintImpl(names, excludes, visited)) {
187 childVisited = true;
190 bool meVisited = childVisited || hdf_is_visited(getRaw());
192 std::string fullname = getFullPath();
193 if (!fullname.empty()) {
194 if (meVisited == visited) {
195 bool excluded = false;
196 for (unsigned int i = 0; i < excludes.size(); i++) {
197 if (match(fullname, excludes[i])) {
198 excluded = true;
199 break;
202 if (!excluded) {
203 if (!visited) {
204 names.resize(size); // so reports about my children are gone
206 names.push_back(fullname);
211 return meVisited;
214 void Hdf::lint(std::vector<std::string> &names,
215 const char *excludePatternNode /* = "LintExcludePatterns" */,
216 bool visited /* = false */) {
217 std::vector<std::string> patterns;
218 if (excludePatternNode && *excludePatternNode) {
219 for (Hdf hdf = operator[](excludePatternNode).firstChild();
220 hdf.exists(); hdf = hdf.next()) {
221 std::string value = hdf.configGetString();
222 if (!value.empty()) {
223 patterns.push_back(value);
228 lintImpl(names, patterns, visited);
231 void Hdf::setVisited(bool visited /* = true */) {
232 hdf_set_visited(getRaw(), visited ? 1 : 0);
233 for (Hdf hdf = firstChild(false); hdf.exists(); hdf = hdf.next(false)) {
234 hdf.setVisited(visited);
238 ///////////////////////////////////////////////////////////////////////////////
239 // gets
241 const char *Hdf::configGet(const char *defValue /* = NULL */) const {
242 HDF *hdf = getRaw();
243 auto err = STATUS_OK;
244 const char *v = hdf_obj_value(hdf, &err);
245 CheckNeoError(err);
246 hdf_set_visited(hdf, 1);
247 return v ? v : defValue;
250 std::string Hdf::configGetString(const std::string &defValue /* = "" */) const {
251 const char *v = configGet();
252 if (v == nullptr) return defValue;
253 return v;
256 bool Hdf::configGetBool(bool defValue /* = false */) const {
257 const char *v = configGet();
258 if (v == nullptr) return defValue;
259 return convertRawConfigToBool(v);
262 int64_t Hdf::getInt(int64_t defValue, const char *type, int64_t maxValue) const {
263 const char *v = configGet();
264 if (v == nullptr) return defValue;
266 char *endptr = nullptr;
267 int64_t n = strtoll(v, &endptr, 0);
268 if ((!endptr && !*endptr) ||
269 (maxValue && (n > maxValue || n < (- maxValue - 1)))) {
270 throw HdfDataTypeException(this, type, v);
273 return n;
276 char Hdf::configGetByte(char defValue /* = 0 */) const {
277 return getInt(defValue, "byte", 0x7FL);
280 int16_t Hdf::configGetInt16(int16_t defValue /* = 0 */) const {
281 return getInt(defValue, "int16", 0x7FFFL);
284 int32_t Hdf::configGetInt32(int32_t defValue /* = 0 */) const {
285 return getInt(defValue, "int32", 0x7FFFFFFFL);
288 int64_t Hdf::configGetInt64(int64_t defValue /* = 0 */) const {
289 return getInt(defValue, "int64", 0);
292 uint64_t Hdf::getUInt(uint64_t defValue, const char *type, uint64_t mask) const {
293 const char *v = configGet();
294 if (v == nullptr) return defValue;
296 char *endptr = nullptr;
297 int64_t n = strtoull(v, &endptr, 0);
298 if ((!endptr && !*endptr) || (mask && ((uint64_t)n & mask))) {
299 throw HdfDataTypeException(this, type, v);
302 return n;
305 unsigned char Hdf::configGetUByte(unsigned char defValue /* = 0 */) const {
306 return getUInt(defValue, "unsigned byte", ~0xFFUL);
309 uint16_t Hdf::configGetUInt16(uint16_t defValue /* = 0 */) const {
310 return getUInt(defValue, "unsigned int16", ~0xFFFFUL);
313 uint32_t Hdf::configGetUInt32(uint32_t defValue /* = 0 */) const {
314 return getUInt(defValue, "unsigned int32", ~0xFFFFFFFFUL);
317 uint64_t Hdf::configGetUInt64(uint64_t defValue /* = 0 */) const {
318 return getUInt(defValue, "unsigned int64", 0);
321 double Hdf::configGetDouble(double defValue /* = 0 */) const {
322 const char *v = configGet();
323 if (v == nullptr) return defValue;
325 char *endptr = nullptr;
326 double n = strtod(v, &endptr);
327 if (!endptr && !*endptr) {
328 throw HdfDataTypeException(this, "double", v);
331 return n;
334 void Hdf::configGet(std::vector<uint32_t> &values) const {
335 values.clear();
336 for (Hdf hdf = firstChild(); hdf.exists(); hdf = hdf.next()) {
337 values.push_back(hdf.configGetUInt32(0));
341 void Hdf::configGet(std::vector<std::string> &values) const {
342 values.clear();
343 for (Hdf hdf = firstChild(); hdf.exists(); hdf = hdf.next()) {
344 values.push_back(hdf.configGetString(""));
348 void Hdf::configGet(std::set<std::string> &values) const {
349 values.clear();
350 for (Hdf hdf = firstChild(); hdf.exists(); hdf = hdf.next()) {
351 values.insert(hdf.configGetString(""));
355 void Hdf::configGet(boost::container::flat_set<std::string> &values) const {
356 values.clear();
357 for (Hdf hdf = firstChild(); hdf.exists(); hdf = hdf.next()) {
358 values.insert(hdf.configGetString(""));
362 void Hdf::configGet(std::unordered_map<std::string, int> &values) const {
363 values.clear();
364 for (Hdf hdf = firstChild(); hdf.exists(); hdf = hdf.next()) {
365 values[hdf.getName()] = hdf.configGetInt32();
369 void Hdf::configGet(std::set<std::string, stdltistr> &values) const {
370 values.clear();
371 for (Hdf hdf = firstChild(); hdf.exists(); hdf = hdf.next()) {
372 values.insert(hdf.configGetString(""));
376 void Hdf::configGet(std::map<std::string, std::string> &values) const {
377 values.clear();
378 for (Hdf hdf = firstChild(); hdf.exists(); hdf = hdf.next()) {
379 values[hdf.getName()] = hdf.configGetString("");
383 void Hdf::configGet(std::map<std::string, std::string,
384 stdltistr> &values) const {
385 values.clear();
386 for (Hdf hdf = firstChild(); hdf.exists(); hdf = hdf.next()) {
387 values[hdf.getName()] = hdf.configGetString("");
391 void Hdf::configGet(hphp_string_imap<std::string> &values) const {
392 values.clear();
393 for (Hdf hdf = firstChild(); hdf.exists(); hdf = hdf.next()) {
394 values[hdf.getName()] = hdf.configGetString("");
398 bool Hdf::convertRawConfigToBool(const char *v) {
399 return *v && strcmp(v, "0") &&
400 strcasecmp(v, "false") && strcasecmp(v, "no") && strcasecmp(v, "off");
403 int Hdf::compare(const char *v2) const {
404 const char *v1 = configGet();
405 if (v1 == nullptr && v2 == nullptr) return 0;
406 if (v1 == nullptr) return -1;
407 if (v2 == nullptr) return 1;
408 return strcmp(v1, v2);
411 int Hdf::compare(const std::string &v2) const {
412 std::string v1 = configGetString();
413 return strcmp(v1.c_str(), v2.c_str());
416 int Hdf::compare(char v2) const {
417 char v1 = configGetByte();
418 if (v1 == v2) return 0;
419 return v1 > v2 ? 1 : -1;
422 int Hdf::compare(unsigned char v2) const {
423 unsigned char v1 = configGetUByte();
424 if (v1 == v2) return 0;
425 return v1 > v2 ? 1 : -1;
428 int Hdf::compare(int16_t v2) const {
429 int16_t v1 = configGetInt16();
430 if (v1 == v2) return 0;
431 return v1 > v2 ? 1 : -1;
434 int Hdf::compare(uint16_t v2) const {
435 uint16_t v1 = configGetUInt16();
436 if (v1 == v2) return 0;
437 return v1 > v2 ? 1 : -1;
440 int Hdf::compare(int32_t v2) const {
441 int32_t v1 = configGetInt32();
442 if (v1 == v2) return 0;
443 return v1 > v2 ? 1 : -1;
446 int Hdf::compare(uint32_t v2) const {
447 uint32_t v1 = configGetUInt32();
448 if (v1 == v2) return 0;
449 return v1 > v2 ? 1 : -1;
452 int Hdf::compare(int64_t v2) const {
453 int64_t v1 = configGetInt64();
454 if (v1 == v2) return 0;
455 return v1 > v2 ? 1 : -1;
458 int Hdf::compare(uint64_t v2) const {
459 uint64_t v1 = configGetUInt64();
460 if (v1 == v2) return 0;
461 return v1 > v2 ? 1 : -1;
464 int Hdf::compare(double v2) const {
465 double v1 = configGetDouble();
466 if (v1 == v2) return 0;
467 return v1 > v2 ? 1 : -1;
470 ///////////////////////////////////////////////////////////////////////////////
471 // sets
473 Hdf &Hdf::operator=(const Hdf &hdf) {
474 if (&hdf != this) {
475 if (m_rawp != hdf.m_rawp) {
476 if (m_rawp) {
477 m_rawp->dec();
479 m_rawp = hdf.m_rawp;
480 if (m_rawp) {
481 m_rawp->inc();
485 m_hdf = hdf.m_hdf;
486 m_path = hdf.m_path;
487 m_name = hdf.m_name;
489 if (m_dump) {
490 free(m_dump);
492 m_dump = nullptr;
494 return *this;
497 void Hdf::set(const char *value) {
498 CheckNeoError(hdf_set_value(getRaw(), nullptr, (char*)value));
501 void Hdf::set(int64_t value) {
502 char buf[24];
503 snprintf(buf, sizeof(buf), "%lld", (long long)value);
504 set(buf);
507 void Hdf::set(uint64_t value) {
508 char buf[24];
509 snprintf(buf, sizeof(buf), "%llu", (unsigned long long)value);
510 set(buf);
513 void Hdf::set(double value) {
514 char buf[32];
515 snprintf(buf, sizeof(buf), "%g", value);
516 set(buf);
519 ///////////////////////////////////////////////////////////////////////////////
520 // sub-nodes
522 std::string Hdf::getName(bool markVisited /* = true */) const {
523 HDF *hdf = getRaw();
524 char *name = hdf_obj_name(hdf);
525 if (markVisited) hdf_set_visited(hdf, 1);
526 return name ? name : "";
529 std::string Hdf::getFullPath() const {
530 std::string fullpath;
531 if (m_path.empty()) {
532 fullpath = m_name;
533 } else {
534 fullpath = m_path;
535 if (!m_name.empty()) {
536 fullpath += ".";
537 fullpath += m_name;
540 return fullpath;
543 Hdf Hdf::parentImpl() const {
544 Hdf hdf(*this);
545 if (m_name.empty()) {
546 if (m_path.empty()) {
547 throw HdfInvalidOperation("calling parent() on topmost node");
549 size_t pos = m_path.rfind('.');
550 if (pos == std::string::npos) {
551 hdf.m_name = m_path;
552 hdf.m_path.clear();
553 } else {
554 hdf.m_name = m_path.substr(pos + 1);
555 hdf.m_path = m_path.substr(0, pos);
557 } else {
558 hdf.m_name.clear();
560 return hdf;
563 const Hdf Hdf::parent() const {
564 return parentImpl();
567 Hdf Hdf::parent() {
568 return parentImpl();
571 const Hdf Hdf::operator[](int name) const {
572 char buf[12];
573 sprintf(buf, "%d", name);
574 return operator[](buf);
577 const Hdf Hdf::operator[](const char *name) const {
578 return Hdf(this, name);
581 const Hdf Hdf::operator[](const std::string &name) const {
582 return operator[](name.c_str());
585 Hdf Hdf::operator[](int name) {
586 char buf[12];
587 sprintf(buf, "%d", name);
588 return operator[](buf);
591 Hdf Hdf::operator[](const char *name) {
592 return Hdf(this, name);
595 Hdf Hdf::operator[](const std::string &name) {
596 return operator[](name.c_str());
599 bool Hdf::exists() const {
600 if (m_rawp == nullptr) {
601 return m_hdf != nullptr;
604 std::string fullpath = getFullPath();
605 if (fullpath.empty()) {
606 return true;
609 auto err = STATUS_OK;
610 auto const result = hdf_get_obj(m_rawp->m_hdf, fullpath.c_str(), &err);
611 CheckNeoError(err);
612 return result;
615 bool Hdf::exists(int name) const {
616 char buf[12];
617 sprintf(buf, "%d", name);
618 return exists(buf);
621 bool Hdf::exists(const char *name) const {
622 HDF *hdf = m_hdf;
623 if (m_rawp) {
624 std::string fullpath = getFullPath();
625 hdf = m_rawp->m_hdf;
626 if (!fullpath.empty()) {
627 auto err = STATUS_OK;
628 hdf = hdf_get_obj(hdf, fullpath.c_str(), &err);
629 CheckNeoError(err);
632 if (!hdf) return false;
633 auto err = STATUS_OK;
634 if (hdf_get_obj(hdf, name, &err)) return true;
635 CheckNeoError(err);
636 return false;
639 bool Hdf::exists(const std::string &name) const {
640 return exists(name.c_str());
643 void Hdf::remove(int name) const {
644 char buf[12];
645 sprintf(buf, "%d", name);
646 remove(buf);
649 void Hdf::remove(const char *name) const {
650 assert(name && *name);
651 CheckNeoError(hdf_remove_tree(getRaw(), name));
654 void Hdf::remove(const std::string &name) const {
655 remove(name.c_str());
658 ///////////////////////////////////////////////////////////////////////////////
659 // iterations
661 Hdf Hdf::firstChild(bool markVisited /* = true */) const {
662 HDF *hdf = getRaw();
663 if (markVisited) hdf_set_visited(hdf, 1);
664 auto err = STATUS_OK;
665 auto child = hdf_obj_child(hdf, &err);
666 CheckNeoError(err);
667 Hdf ret(child);
668 ret.m_path = getFullPath();
669 ret.m_name = ret.getName(markVisited);
670 return ret;
673 Hdf Hdf::next(bool markVisited /* = true */) const {
674 HDF *hdf = getRaw();
675 if (markVisited) hdf_set_visited(hdf, 1);
676 Hdf ret(hdf_obj_next(hdf));
677 ret.m_path = m_path;
678 ret.m_name = ret.getName(markVisited);
679 return ret;
682 ///////////////////////////////////////////////////////////////////////////////
683 // input/output
685 void Hdf::fromString(const char *input) {
686 CheckNeoError(hdf_read_string(getRaw(), (char*)input));
689 const char *Hdf::toString() const {
690 if (m_dump) {
691 free(m_dump);
692 m_dump = nullptr;
694 CheckNeoError(hdf_write_string(getRaw(), &m_dump));
695 return m_dump;
698 void Hdf::write(const char *filename) const {
699 CheckNeoError(hdf_write_file(getRaw(), filename));
702 ///////////////////////////////////////////////////////////////////////////////
703 // helpers
705 HDF *Hdf::getRaw() const {
706 if (m_hdf) return m_hdf;
708 if (m_rawp == nullptr) {
709 return nullptr;
712 HDF *ret = nullptr;
713 std::string fullpath = getFullPath();
714 if (fullpath.empty()) {
715 ret = m_rawp->m_hdf;
716 } else {
717 CheckNeoError(hdf_get_node(m_rawp->m_hdf, (char*)fullpath.c_str(), &ret));
719 m_hdf = ret;
720 return ret;
723 void Hdf::CheckNeoError(NEOERR *err) {
724 if (err != STATUS_OK) {
725 NEOSTRING str;
726 string_init(&str);
727 nerr_error_string(err, &str);
728 throw HdfException("%s", str.buf);
732 ///////////////////////////////////////////////////////////////////////////////
733 // exceptions
735 HdfException::HdfException(const char *fmt, ...) {
736 va_list ap; va_start(ap, fmt); format(fmt, ap); va_end(ap);
739 ///////////////////////////////////////////////////////////////////////////////