fix compile error #4
@ -52,8 +52,8 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
|||||||
set(WHOLE_ARCHIVE_PREFIX "-Wl,-force_load,")
|
set(WHOLE_ARCHIVE_PREFIX "-Wl,-force_load,")
|
||||||
# set(NO_WHOLE_ARCHIVE_PREFIX "")
|
# set(NO_WHOLE_ARCHIVE_PREFIX "")
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -gz")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -gz")
|
||||||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -gz")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -gz")
|
||||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
||||||
# set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
# set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
|
||||||
|
|
||||||
@ -153,6 +153,7 @@ set(TILE_SRCS
|
|||||||
"tile/base/encoding/detail/hex_chars.cc"
|
"tile/base/encoding/detail/hex_chars.cc"
|
||||||
"tile/base/encoding/hex.cc"
|
"tile/base/encoding/hex.cc"
|
||||||
"tile/base/encoding/percent.cc"
|
"tile/base/encoding/percent.cc"
|
||||||
|
"tile/base/exposed_var.cc"
|
||||||
"tile/base/internal/background_task_host.cc"
|
"tile/base/internal/background_task_host.cc"
|
||||||
"tile/base/internal/background_task_host.h"
|
"tile/base/internal/background_task_host.h"
|
||||||
"tile/base/internal/case_insensitive_hash_map.h"
|
"tile/base/internal/case_insensitive_hash_map.h"
|
||||||
@ -283,7 +284,8 @@ if(TILE_BUILD_TESTS)
|
|||||||
add_test(NAME ${test_name} COMMAND ${test_name})
|
add_test(NAME ${test_name} COMMAND ${test_name})
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
tile_add_test(fiber_detail_scheduler_test "tile/fiber/detail/scheduler_test.cc")
|
tile_add_test(base_exposed_var_test "tile/base/exposed_var_test.cc")
|
||||||
|
tile_add_test(fiber_detail_scheduler_test "tile/fiber/detail/scheduler_test.cc")
|
||||||
tile_add_test(base_internal_meta_test "tile/base/internal/meta_test.cc")
|
tile_add_test(base_internal_meta_test "tile/base/internal/meta_test.cc")
|
||||||
# tile_add_test(net_internal_http_engine_test
|
# tile_add_test(net_internal_http_engine_test
|
||||||
# "tile/net/internal/http_engine_test.cc")
|
# "tile/net/internal/http_engine_test.cc")
|
||||||
|
6
third_party/glog/CMakeLists.txt
vendored
6
third_party/glog/CMakeLists.txt
vendored
@ -39,7 +39,7 @@ option(PRINT_UNSYMBOLIZED_STACK_TRACES
|
|||||||
"Print file offsets in traces instead of symbolizing" OFF)
|
"Print file offsets in traces instead of symbolizing" OFF)
|
||||||
option(WITH_CUSTOM_PREFIX "Enable support for user-generated message prefixes"
|
option(WITH_CUSTOM_PREFIX "Enable support for user-generated message prefixes"
|
||||||
ON)
|
ON)
|
||||||
option(WITH_GFLAGS "Use gflags" ON)
|
option(WITH_GFLAGS "Use gflags" OFF)
|
||||||
option(WITH_GTEST "Use Google Test" OFF)
|
option(WITH_GTEST "Use Google Test" OFF)
|
||||||
option(WITH_PKGCONFIG "Enable pkg-config support" OFF)
|
option(WITH_PKGCONFIG "Enable pkg-config support" OFF)
|
||||||
option(WITH_SYMBOLIZE "Enable symbolize module" ON)
|
option(WITH_SYMBOLIZE "Enable symbolize module" ON)
|
||||||
@ -699,8 +699,8 @@ endif(HAVE_PTHREAD)
|
|||||||
|
|
||||||
if(gflags_FOUND)
|
if(gflags_FOUND)
|
||||||
# Prefer the gflags target that uses double colon convention
|
# Prefer the gflags target that uses double colon convention
|
||||||
# target_link_libraries(glog PRIVATE gflags::gflags)
|
# target_link_libraries(glog PRIVATE gflags::gflags)
|
||||||
# if (TARGET
|
# if (TARGET
|
||||||
# gflags::gflags) target_link_libraries (glog PUBLIC gflags::gflags) else
|
# gflags::gflags) target_link_libraries (glog PUBLIC gflags::gflags) else
|
||||||
# (TARGET gflags::gflags) target_link_libraries (glog PUBLIC gflags) endif
|
# (TARGET gflags::gflags) target_link_libraries (glog PUBLIC gflags) endif
|
||||||
# (TARGET gflags::gflags)
|
# (TARGET gflags::gflags)
|
||||||
|
7
third_party/json/json.h
vendored
7
third_party/json/json.h
vendored
@ -1,7 +0,0 @@
|
|||||||
#ifndef TILE__THIRD_PARTY_JSON_JSON_H
|
|
||||||
#define TILE__THIRD_PARTY_JSON_JSON_H
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "nlohmann/json.hpp"
|
|
||||||
|
|
||||||
#endif // TILE__THIRD_PARTY_JSON_JSON_H
|
|
24765
third_party/json/nlohmann/json.hpp
vendored
24765
third_party/json/nlohmann/json.hpp
vendored
File diff suppressed because it is too large
Load Diff
300
tile/base/exposed_var.cc
Normal file
300
tile/base/exposed_var.cc
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
#include "tile/base/exposed_var.h"
|
||||||
|
|
||||||
|
#include "tile/base/internal/logging.h"
|
||||||
|
#include "tile/base/internal/move_on_copy.h"
|
||||||
|
#include "tile/base/string.h"
|
||||||
|
|
||||||
|
namespace tile {
|
||||||
|
// namespace exposed_var {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
#define CHECK_PATH(path) \
|
||||||
|
TILE_CHECK((path).size() <= 1 || (path).back() != '/', \
|
||||||
|
"Invalid path: [{}].", path); \
|
||||||
|
TILE_CHECK((path).find("//") == tile::Slice::npos, "Invalid path: [{}].", \
|
||||||
|
path);
|
||||||
|
|
||||||
|
#define CHECK_RELATIVE_PATH(path) \
|
||||||
|
CHECK_PATH(path); \
|
||||||
|
TILE_CHECK((path).empty() || (path).front() != '/', "Invalid path: [{}].", \
|
||||||
|
path);
|
||||||
|
|
||||||
|
#define CHECK_ABSOLUTE_PATH(path) \
|
||||||
|
CHECK_PATH(path); \
|
||||||
|
TILE_CHECK((path).empty() || (path).front() == '/', "Invalid path: [{}]", \
|
||||||
|
path);
|
||||||
|
|
||||||
|
std::pair<Slice, Slice> SplitFirstPart(Slice path) {
|
||||||
|
auto pos = path.find_first_of('/');
|
||||||
|
if (pos == tile::Slice::npos) {
|
||||||
|
return std::make_pair(path, "");
|
||||||
|
} else {
|
||||||
|
return std::make_pair(path.substr(0, pos), path.substr(pos + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<Slice, Slice> SplitLastPart(Slice path) {
|
||||||
|
auto pos = path.find_last_of('/');
|
||||||
|
if (pos == tile::Slice::npos) {
|
||||||
|
return std::make_pair("", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(path.substr(0, pos), path.substr(pos + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string JoinPath(Slice a, Slice b) {
|
||||||
|
if (EndsWith(b, "/")) {
|
||||||
|
b.RemoveSuffix(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EndsWith(a, "/")) {
|
||||||
|
a.RemoveSuffix(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.empty()) {
|
||||||
|
return a.ToString();
|
||||||
|
}
|
||||||
|
if (a.empty()) {
|
||||||
|
return b.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.ToString() + "/" + b.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SubstituteEscapedSlashForZero(Slice path) {
|
||||||
|
TILE_CHECK(path.find('\0') == tile::Slice::npos);
|
||||||
|
return Replace(path, "\\/", '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SubstituteZeroForEscapedSlash(Slice path) {
|
||||||
|
return Replace(path, '\0', "\\/");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string UnescapeZeroToPlainSlash(Slice path) {
|
||||||
|
return Replace(path, '\0', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// } // namespace exposed_var
|
||||||
|
ExposedVarGroup::Handle
|
||||||
|
ExposedVarGroup::Add(Slice rel_path, std::function<Json::Value()> value) {
|
||||||
|
|
||||||
|
auto real_path = SubstituteEscapedSlashForZero(rel_path);
|
||||||
|
CHECK_RELATIVE_PATH(rel_path);
|
||||||
|
|
||||||
|
auto path_and_name = SplitLastPart(real_path);
|
||||||
|
auto name = path_and_name.second.ToString();
|
||||||
|
|
||||||
|
auto moved_func = tile::MakeMoveOnCopy(value);
|
||||||
|
return CreateUpto(path_and_name.first)
|
||||||
|
->AddDirect(
|
||||||
|
name,
|
||||||
|
[name, moved_func](Slice expected) -> std::optional<Json::Value> {
|
||||||
|
auto jsv = moved_func.Ref()();
|
||||||
|
if (expected.empty()) {
|
||||||
|
return jsv;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto real_path = SubstituteEscapedSlashForZero(expected);
|
||||||
|
Json::Value *ptr = &jsv;
|
||||||
|
auto pieces = Split(real_path, '/');
|
||||||
|
|
||||||
|
for (auto &&e : pieces) {
|
||||||
|
auto unescaped = UnescapeZeroToPlainSlash({e.data(), e.size()});
|
||||||
|
if (ptr->isObject()) {
|
||||||
|
if (ptr->isMember(unescaped)) {
|
||||||
|
ptr = &(*ptr)[unescaped];
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} else if (ptr->isArray()) {
|
||||||
|
auto index = TryParse<std::size_t>(unescaped);
|
||||||
|
if (index && *index < ptr->size()) {
|
||||||
|
ptr = &(*ptr)[static_cast<Json::ArrayIndex>(*index)];
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ExposedVarGroup::Handle
|
||||||
|
ExposedVarGroup::Add(Slice rel_path, ExposedVarDynamicTree *dynamic_tree) {
|
||||||
|
auto real_path = SubstituteEscapedSlashForZero(rel_path);
|
||||||
|
CHECK_RELATIVE_PATH(real_path);
|
||||||
|
auto path_and_name = SplitLastPart(real_path);
|
||||||
|
auto name = path_and_name.second.ToString();
|
||||||
|
|
||||||
|
return CreateUpto(path_and_name.first)
|
||||||
|
->AddDirect(name, [dynamic_tree](Slice inner_path) {
|
||||||
|
return dynamic_tree->TryGet(inner_path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ExposedVarGroup *ExposedVarGroup::FindOrCreate(Slice abs_path) {
|
||||||
|
auto real_path = SubstituteEscapedSlashForZero(abs_path);
|
||||||
|
CHECK_ABSOLUTE_PATH(real_path);
|
||||||
|
|
||||||
|
return Root()->CreateUpto(real_path.substr(1));
|
||||||
|
}
|
||||||
|
std::optional<Json::Value> ExposedVarGroup::TryGet(Slice abs_path) {
|
||||||
|
auto real_path = SubstituteEscapedSlashForZero(abs_path);
|
||||||
|
TILE_CHECK(!real_path.empty());
|
||||||
|
CHECK_ABSOLUTE_PATH(real_path);
|
||||||
|
|
||||||
|
if (real_path == "/") {
|
||||||
|
return Root()->Dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
Slice left_path;
|
||||||
|
auto rel_path = real_path.substr(1);
|
||||||
|
auto parent = Root()->FindLowest(rel_path, &left_path);
|
||||||
|
|
||||||
|
auto name_and_rest = SplitFirstPart(left_path);
|
||||||
|
if (name_and_rest.first.empty()) {
|
||||||
|
return parent->Dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto s = name_and_rest.first.ToString();
|
||||||
|
std::lock_guard<std::mutex> lk(parent->lock_);
|
||||||
|
auto iter = parent->leaves_.find(s);
|
||||||
|
if (iter != parent->leaves_.end()) {
|
||||||
|
return iter->second(SubstituteZeroForEscapedSlash(name_and_rest.second));
|
||||||
|
} else {
|
||||||
|
auto iter = parent->nodes_.find(s);
|
||||||
|
if (iter != parent->nodes_.end()) {
|
||||||
|
return iter->second->Dump();
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExposedVarGroup::ExposedVarGroup(std::string abs_path)
|
||||||
|
: abs_path_(std::move(abs_path)) {
|
||||||
|
CHECK_ABSOLUTE_PATH(abs_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExposedVarGroup *ExposedVarGroup::Root() {
|
||||||
|
static ExposedVarGroup evg("/");
|
||||||
|
return &evg;
|
||||||
|
}
|
||||||
|
const std::string &ExposedVarGroup::AbsolutePath() const { return abs_path_; }
|
||||||
|
|
||||||
|
ExposedVarGroup *ExposedVarGroup::FindLowest(Slice rel_path, Slice *left) {
|
||||||
|
CHECK_RELATIVE_PATH(rel_path);
|
||||||
|
auto current = this;
|
||||||
|
|
||||||
|
while (!rel_path.empty()) {
|
||||||
|
auto name_and_rest = SplitFirstPart(rel_path);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lk(current->lock_);
|
||||||
|
auto iter = current->nodes_.find(name_and_rest.first.ToString());
|
||||||
|
if (iter == current->nodes_.end()) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
current = &*iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
rel_path = name_and_rest.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left) {
|
||||||
|
*left = rel_path;
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExposedVarGroup *ExposedVarGroup::CreateUpto(Slice rel_path) {
|
||||||
|
CHECK_RELATIVE_PATH(rel_path);
|
||||||
|
|
||||||
|
Slice left_path;
|
||||||
|
auto current = FindLowest(rel_path, &left_path);
|
||||||
|
|
||||||
|
auto pieces = Split(left_path, '/');
|
||||||
|
|
||||||
|
for (auto &&e : pieces) {
|
||||||
|
auto s = e.ToString();
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lk(current->lock_);
|
||||||
|
auto p = JoinPath(current->AbsolutePath(), s);
|
||||||
|
|
||||||
|
TILE_CHECK(
|
||||||
|
current->leaves_.find(s) == current->leaves_.end(),
|
||||||
|
"Path [{}] has already been used: A value is registered at [{}].",
|
||||||
|
rel_path, p);
|
||||||
|
|
||||||
|
TILE_CHECK(current->nodes_.find(s) == current->nodes_.end());
|
||||||
|
auto evg = std::unique_ptr<ExposedVarGroup>(new ExposedVarGroup(p));
|
||||||
|
current->nodes_[s] = std::move(evg);
|
||||||
|
current = &*(current->nodes_[s]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TILE_CHECK(EndsWith(current->AbsolutePath(), rel_path), "[{}] vs [{}]",
|
||||||
|
current->AbsolutePath(), rel_path);
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExposedVarGroup::Handle ExposedVarGroup::AddDirect(Slice name, Getter value) {
|
||||||
|
auto s = name.ToString();
|
||||||
|
std::lock_guard<std::mutex> lk(lock_);
|
||||||
|
|
||||||
|
TILE_CHECK(leaves_.find(s) == leaves_.end(),
|
||||||
|
"Value [{}] has already been registered at [{}].", name,
|
||||||
|
AbsolutePath());
|
||||||
|
TILE_CHECK(nodes_.find(s) == nodes_.end(), "Path [{}] has already been used.",
|
||||||
|
JoinPath(AbsolutePath(), name));
|
||||||
|
leaves_[s] = std::move(value);
|
||||||
|
|
||||||
|
return Deferred([this, s] {
|
||||||
|
std::lock_guard<std::mutex> lk(lock_);
|
||||||
|
TILE_CHECK_EQ(leaves_.erase(s), 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value ExposedVarGroup::Dump() const {
|
||||||
|
std::lock_guard<std::mutex> lk(lock_);
|
||||||
|
Json::Value jsv;
|
||||||
|
for (auto &&node : nodes_) {
|
||||||
|
jsv[UnescapeZeroToPlainSlash(node.first)] = node.second->Dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &&leave : leaves_) {
|
||||||
|
jsv[UnescapeZeroToPlainSlash(leave.first)] = *leave.second("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsv;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExposedVarDynamicTree::ExposedVarDynamicTree(
|
||||||
|
Slice rel_path, std::function<Json::Value()> getter,
|
||||||
|
ExposedVarGroup *parent)
|
||||||
|
: getter_(std::move(getter)) {
|
||||||
|
handle_ = parent->Add(rel_path, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Json::Value> ExposedVarDynamicTree::TryGet(Slice rel_path) const {
|
||||||
|
auto real_path = SubstituteEscapedSlashForZero(rel_path);
|
||||||
|
auto jsv = getter_();
|
||||||
|
Json::Value *ptr = &jsv;
|
||||||
|
|
||||||
|
auto pieces = Split(real_path, '/');
|
||||||
|
for (auto &&e : pieces) {
|
||||||
|
auto unescaped = UnescapeZeroToPlainSlash({e.data(), e.size()});
|
||||||
|
ptr = &(*ptr)[unescaped];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr->isNull()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tile
|
@ -3,14 +3,191 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "inja/inja.h"
|
#include "tile/base/chrono.h"
|
||||||
|
#include "tile/base/deferred.h"
|
||||||
|
#include "tile/base/internal/meta.h"
|
||||||
|
#include "tile/base/optional.h"
|
||||||
|
#include "tile/base/slice.h"
|
||||||
|
#include "json/value.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace tile {
|
namespace tile {
|
||||||
namespace exposed_var {
|
namespace exposed_var {
|
||||||
template <typename T> inja::json ToJson(const T &t) {
|
|
||||||
|
template <typename T>
|
||||||
|
auto ToJsonValue(const T &t)
|
||||||
|
-> enable_if_t<std::is_same<T, Json::Value>::value, Json::Value> {
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto ToJsonValue(const T &t)
|
||||||
|
-> enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value,
|
||||||
|
Json::Value> {
|
||||||
|
return Json::Value(static_cast<Json::UInt64>(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto ToJsonValue(const T &t)
|
||||||
|
-> enable_if_t<std::is_integral<T>::value && !std::is_unsigned<T>::value,
|
||||||
|
Json::Value> {
|
||||||
|
return Json::Value(static_cast<Json::Int64>(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto ToJsonValue(const T &t)
|
||||||
|
-> enable_if_t<std::is_floating_point<T>::value ||
|
||||||
|
std::is_same<T, std::string>::value ||
|
||||||
|
std::is_same<T, const char *>::value ||
|
||||||
|
std::is_same<T, bool>::value,
|
||||||
|
Json::Value> {
|
||||||
|
return Json::Value(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto ToJsonValue(const T &t)
|
||||||
|
-> enable_if_t<
|
||||||
|
!std::is_integral<T>::value && !std::is_floating_point<T>::value &&
|
||||||
|
!std::is_same<T, std::string>::value &&
|
||||||
|
!std::is_same<T, const char *>::value &&
|
||||||
|
!std::is_same<T, bool>::value &&
|
||||||
|
std::is_same<std::string,
|
||||||
|
decltype(format_as(std::declval<T>()))>::value,
|
||||||
|
Json::Value> {
|
||||||
|
return Json::Value(format_as(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> Json::Value ToJsonValue(const std::atomic<T> &v) {
|
||||||
|
return ToJsonValue(v.load(std::memory_order_relaxed));
|
||||||
|
}
|
||||||
} // namespace exposed_var
|
} // namespace exposed_var
|
||||||
|
|
||||||
|
class ExposedVarDynamicTree;
|
||||||
|
|
||||||
|
class ExposedVarGroup {
|
||||||
|
public:
|
||||||
|
using Handle = Deferred;
|
||||||
|
|
||||||
|
Handle Add(Slice rel_path, std::function<Json::Value()> value);
|
||||||
|
Handle Add(Slice rel_path, ExposedVarDynamicTree *dyanmic_tree);
|
||||||
|
static ExposedVarGroup *FindOrCreate(Slice abs_path);
|
||||||
|
static std::optional<Json::Value> TryGet(Slice abs_path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Getter = std::function<std::optional<Json::Value>(Slice)>;
|
||||||
|
|
||||||
|
explicit ExposedVarGroup(std::string abs_path);
|
||||||
|
const std::string &AbsolutePath() const;
|
||||||
|
|
||||||
|
ExposedVarGroup *FindLowest(Slice rel_path, Slice *left);
|
||||||
|
ExposedVarGroup *CreateUpto(Slice rel_path);
|
||||||
|
Handle AddDirect(Slice name, Getter getter);
|
||||||
|
Json::Value Dump() const;
|
||||||
|
static ExposedVarGroup *Root();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string abs_path_;
|
||||||
|
mutable std::mutex lock_;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<ExposedVarGroup>> nodes_;
|
||||||
|
std::unordered_map<std::string, Getter> leaves_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class ExposedVar {
|
||||||
|
public:
|
||||||
|
ExposedVar(Slice rel_path) {
|
||||||
|
LinkToParent(rel_path, ExposedVarGroup::FindOrCreate("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
ExposedVar(Slice rel_path, U &&initial_value,
|
||||||
|
ExposedVarGroup *parent = ExposedVarGroup::FindOrCreate("/"))
|
||||||
|
: obj_(std::forward<U>(initial_value)) {
|
||||||
|
LinkToParent(rel_path, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
T *operator->() noexcept { return &obj_; }
|
||||||
|
T &operator*() noexcept { return obj_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void LinkToParent(Slice rel_path, ExposedVarGroup *parent) {
|
||||||
|
handle_ = parent->Add(rel_path,
|
||||||
|
[this] { return exposed_var::ToJsonValue(obj_); });
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T obj_{};
|
||||||
|
ExposedVarGroup::Handle handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class ExposedVarDynamic {
|
||||||
|
public:
|
||||||
|
ExposedVarDynamic(
|
||||||
|
Slice rel_path, std::function<T()> getter,
|
||||||
|
ExposedVarGroup *parent = ExposedVarGroup::FindOrCreate("/"))
|
||||||
|
: getter_(std::move(getter)) {
|
||||||
|
handle_ = parent->Add(
|
||||||
|
rel_path, [this] { return exposed_var::ToJsonValue(getter_()); });
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<T()> getter_;
|
||||||
|
ExposedVarGroup::Handle handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExposedVarDynamicTree {
|
||||||
|
public:
|
||||||
|
ExposedVarDynamicTree(
|
||||||
|
Slice rel_path, std::function<Json::Value()> getter,
|
||||||
|
ExposedVarGroup *parent = ExposedVarGroup::FindOrCreate("/"));
|
||||||
|
|
||||||
|
std::optional<Json::Value> TryGet(Slice rel_path) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<Json::Value()> getter_;
|
||||||
|
ExposedVarGroup::Handle handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template <typename T> struct IdentityTime {
|
||||||
|
std::uint64_t operator()(const T &val) const {
|
||||||
|
return (ReadSteadyClock() - std::chrono::steady_clock::time_point()) /
|
||||||
|
std::chrono::nanoseconds(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename T, typename F = detail::IdentityTime<T>>
|
||||||
|
class ExposedMetrics {
|
||||||
|
public:
|
||||||
|
explicit ExposedMetrics(Slice rel_path) {
|
||||||
|
LinkToParent(rel_path, ExposedVarGroup::FindOrCreate("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Json::Value ToJsonValue(const T &v) {
|
||||||
|
Json::Value result;
|
||||||
|
std::unordered_map<std::string, T> m = {{"1s", 1}};
|
||||||
|
for (auto &&item : m) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinkToParent(Slice rel_path, ExposedVarGroup *parent) {
|
||||||
|
handle_ = parent->Add(rel_path, [this] { return ToJsonValue(obj_); });
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T obj_{};
|
||||||
|
ExposedVarGroup::Handle handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> using ExposedCounter = ExposedVar<T>;
|
||||||
|
template <typename T> using ExposedGauge = ExposedVar<T>;
|
||||||
|
template <typename T> using ExposedMiner = ExposedVar<T>;
|
||||||
|
template <typename T> using ExposedMaxer = ExposedVar<T>;
|
||||||
|
template <typename T> using ExposedAverager = ExposedVar<T>;
|
||||||
|
|
||||||
} // namespace tile
|
} // namespace tile
|
||||||
|
|
||||||
#endif // TILE_BASE_EXPOSED_VAR_H
|
#endif // TILE_BASE_EXPOSED_VAR_H
|
||||||
|
38
tile/base/exposed_var_test.cc
Normal file
38
tile/base/exposed_var_test.cc
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "tile/base/exposed_var.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "json/json.h"
|
||||||
|
|
||||||
|
namespace tile {
|
||||||
|
ExposedVarGroup *GetFancyGroup() {
|
||||||
|
return ExposedVarGroup::FindOrCreate("/a/b");
|
||||||
|
}
|
||||||
|
Json::Value GetTree() {
|
||||||
|
Json::Value jsv;
|
||||||
|
jsv["dir"]["sub-dir"]["key"] = 5;
|
||||||
|
jsv["key"] = "6";
|
||||||
|
return jsv;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExposedVar<int> v1("v1", 5);
|
||||||
|
|
||||||
|
ExposedVar<double> f1("f1", 6.2, ExposedVarGroup::FindOrCreate("/x/y/z"));
|
||||||
|
|
||||||
|
auto GreatGroup = ExposedVarGroup::FindOrCreate("/a/b");
|
||||||
|
|
||||||
|
// `/a/b/ds1`
|
||||||
|
ExposedVarDynamic<std::string>
|
||||||
|
ds1("ds1", [] { return "test_str"; }, GetFancyGroup());
|
||||||
|
|
||||||
|
TEST(ExposedVar, Mutate) {
|
||||||
|
auto opt = ExposedVarGroup::TryGet("/");
|
||||||
|
ASSERT_TRUE(opt);
|
||||||
|
auto &&jsv = *opt;
|
||||||
|
ASSERT_EQ(5, jsv["v1"].asInt());
|
||||||
|
*v1 = 6;
|
||||||
|
jsv = *ExposedVarGroup::TryGet("/");
|
||||||
|
ASSERT_EQ(6, jsv["v1"].asInt());
|
||||||
|
*v1 = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tile
|
@ -91,6 +91,16 @@ public:
|
|||||||
|
|
||||||
constexpr Slice(const Slice &other) : data_(other.data_), len_(other.len_) {}
|
constexpr Slice(const Slice &other) : data_(other.data_), len_(other.len_) {}
|
||||||
|
|
||||||
|
char front() const {
|
||||||
|
assert(len_ > 0);
|
||||||
|
return *data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
char back() const {
|
||||||
|
assert(len_ > 0);
|
||||||
|
return data_[len_ - 1];
|
||||||
|
}
|
||||||
|
|
||||||
Slice &operator=(const Slice &other) {
|
Slice &operator=(const Slice &other) {
|
||||||
data_ = other.data_;
|
data_ = other.data_;
|
||||||
len_ = other.len_;
|
len_ = other.len_;
|
||||||
@ -131,6 +141,8 @@ public:
|
|||||||
|
|
||||||
std::size_t find(Slice s, std::size_t pos = 0) const;
|
std::size_t find(Slice s, std::size_t pos = 0) const;
|
||||||
|
|
||||||
|
std::size_t find_first_of(Slice s) const { return find(s); }
|
||||||
|
|
||||||
// TODO: Optimize it
|
// TODO: Optimize it
|
||||||
std::size_t find_last_of(Slice s) const {
|
std::size_t find_last_of(Slice s) const {
|
||||||
if (s.empty() || s.size() > size()) {
|
if (s.empty() || s.size() > size()) {
|
||||||
|
0
tile/base/write_mostly.h
Normal file
0
tile/base/write_mostly.h
Normal file
36
tile/base/write_mostly/metrics.h
Normal file
36
tile/base/write_mostly/metrics.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef TILE_BASE_WRITE_MOSTLY_METRICS_H
|
||||||
|
#define TILE_BASE_WRITE_MOSTLY_METRICS_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tile/base/internal/meta.h"
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace tile {
|
||||||
|
|
||||||
|
namespace write_mostly {
|
||||||
|
namespace detail {
|
||||||
|
template <typename T> struct MetricsStats;
|
||||||
|
}
|
||||||
|
} // namespace write_mostly
|
||||||
|
|
||||||
|
template <typename T> struct MetricsStats {
|
||||||
|
using SumType = internal::conditional_t<
|
||||||
|
std::is_integral<T>::value,
|
||||||
|
internal::conditional_t<std::is_signed<T>::value, std::int64_t,
|
||||||
|
std::uint64_t>,
|
||||||
|
long double>;
|
||||||
|
|
||||||
|
SumType sum;
|
||||||
|
std::size_t cnt;
|
||||||
|
T max;
|
||||||
|
T min;
|
||||||
|
T average;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace tile
|
||||||
|
|
||||||
|
#endif // TILE_BASE_WRITE_MOSTLY_METRICS_H
|
18
tile/base/write_mostly/write_mostly.h
Normal file
18
tile/base/write_mostly/write_mostly.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef TILE_BASE_WRITE_MOSTLY_WRITE_MOSTLY_H
|
||||||
|
#define TILE_BASE_WRITE_MOSTLY_WRITE_MOSTLY_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace tile {
|
||||||
|
template <typename Traits> class WriteMostly {
|
||||||
|
using T = typename Traits::Type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
};
|
||||||
|
} // namespace tile
|
||||||
|
|
||||||
|
#endif // TILE_BASE_WRITE_MOSTLY_WRITE_MOSTLY_H
|
@ -53,17 +53,22 @@ int Start(int argc, char **argv, std::function<int(int, char **)> cb,
|
|||||||
google::InstallFailureSignalHandler();
|
google::InstallFailureSignalHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init gflags
|
||||||
gflags::SetVersionString("0.1.0");
|
gflags::SetVersionString("0.1.0");
|
||||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||||
detail::ApplyFlagOverrider();
|
detail::ApplyFlagOverrider();
|
||||||
|
|
||||||
|
// Init Glog
|
||||||
google::InitGoogleLogging(argv[0]);
|
google::InitGoogleLogging(argv[0]);
|
||||||
|
|
||||||
TILE_LOG_INFO("Tile started.");
|
TILE_LOG_INFO("Tile started.");
|
||||||
|
|
||||||
TILE_PCHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
|
TILE_PCHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
|
||||||
|
|
||||||
|
// Init BasicRuntime
|
||||||
InitializeBasicRuntime();
|
InitializeBasicRuntime();
|
||||||
|
|
||||||
|
// Run all initializers
|
||||||
detail::RunAllInitializers();
|
detail::RunAllInitializers();
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
@ -11,9 +11,9 @@ namespace testing {
|
|||||||
int InitAndRunAllTests(int *argc, char **argv) {
|
int InitAndRunAllTests(int *argc, char **argv) {
|
||||||
::testing::InitGoogleTest(argc, argv);
|
::testing::InitGoogleTest(argc, argv);
|
||||||
|
|
||||||
if (gflags::GetCommandLineFlagInfoOrDie("logtostderr").is_default) {
|
// if (gflags::GetCommandLineFlagInfoOrDie("logtostderr").is_default) {
|
||||||
FLAGS_logtostderr = true;
|
// FLAGS_logtostderr = true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return Start(*argc, argv, [](int, char **) { return ::RUN_ALL_TESTS(); });
|
return Start(*argc, argv, [](int, char **) { return ::RUN_ALL_TESTS(); });
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user