Make work with string and number keys, cmake

This commit is contained in:
mbandic 2025-04-04 10:06:25 +02:00
parent da9a917945
commit e659a78bd1
9 changed files with 210 additions and 58 deletions

1
.gitignore vendored
View File

@ -0,0 +1 @@
build/

52
.vscode/settings.json vendored
View File

@ -8,6 +8,56 @@
"*.tcc": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"system_error": "cpp"
"system_error": "cpp",
"atomic": "cpp",
"shared_mutex": "cpp",
"mutex": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"array": "cpp",
"bit": "cpp",
"chrono": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"string_view": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"numbers": "cpp",
"semaphore": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"variant": "cpp"
}
}

30
CMakeLists.txt Normal file
View File

@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.10)
project(metrics)
# Postavi verziju projekta
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Pronađi Boost biblioteku (ako nije uobičajeni direktorijum, postavi put)
# find_package(Boost REQUIRED COMPONENTS system)
# Dodaj direktorijume sa zaglavljima
include_directories(lib)
# Dodaj biblioteku
add_library(metrics STATIC
src/metrics.cpp
)
# # Linkaj log biblioteku sa Boost-om
# target_link_libraries(log Boost::system)
# Dodaj testove
add_subdirectory(test)
# Instaliraj biblioteku
# install(TARGETS log DESTINATION lib)
# install(FILES lib/log.hpp lib/define.hpp lib/engine.hpp lib/filesystem.hpp lib/timers.hpp lib/trigger.hpp DESTINATION include/log)
#

View File

@ -27,7 +27,7 @@ using namespace marcelb;
```c++
// init
Metrics stats;
Metrics<string> stats;
// operator [] and increment ++
stats["access"]++;
// print couter access
@ -39,7 +39,7 @@ auto data = stats.get_data();
// reset counters
stats.clear();
// set counters
map<string, uint> MyStats = {{"access", 3},{ "error", 0}};
map<string, uint64_t> MyStats = {{"access", 3},{ "error", 0}};
stats.set(MyStats);
// get and clear all counters
auto dataWithClear = stats.get_data_and_clear();

View File

@ -6,20 +6,22 @@
#include <vector>
#include <map>
#include <mutex>
#include <shared_mutex>
#include <atomic>
using namespace std;
namespace marcelb {
/**
* A class for measuring arbitrary statistics
* A template class for measuring arbitrary statistics
*/
template<typename K>
class Metrics {
mutex io;
map<string, uint> counters;
mutable shared_mutex mtx; // Mutex for concurrent read, exclusive write
map<K, atomic<uint64_t>> counters; // Supports any K (e.g., string, int)
public:
/**
* Constructor, without predefining the name of the counter
*/
@ -28,30 +30,22 @@ class Metrics {
/**
* Constructor, with predefined counters from the passed object
*/
Metrics (map<string, uint> _counters);
Metrics(map<K, uint64_t> _counters);
/**
* Operator[] to access each measurement counter
*/
uint& operator[](const string& key) {
return counters[key];
}
atomic<uint64_t>& operator[](const K& key);
/**
* Operator++ to increment the measurement counter incrementally
*/
Metrics& operator++ (int n) {
lock_guard<mutex> _io(io);
n++;
return *this;
}
Metrics& operator++(int n);
/**
* Method to set the counter from the passed object
*/
void set(map<string, uint> _counters) {
counters = _counters;
}
void set(map<K, uint64_t> _counters);
/**
* A method to reset the counter
@ -59,24 +53,22 @@ class Metrics {
void clear();
/**
* A method that returns a vector os strings of all counter names
* A method that returns a vector of strings of all counter names
*/
vector<string> keys();
vector<K> keys() const;
/**
* The method returns a map<string, uint> of all measurements
* The method returns a map<K, uint64_t> of all measurements
*/
map<string, uint> get_data();
map<K, uint64_t> get_data() const;
/**
* The method returns a map<string, uint> of all measurements and resets the counters
* The method returns a map<K, uint64_t> of all measurements and resets the counters
*/
map<string, uint> get_data_and_clear();
map<K, uint64_t> get_data_and_clear();
};
}
#endif

View File

@ -1,35 +1,78 @@
#include "../lib/metrics.hpp"
marcelb::Metrics::Metrics() {
}
namespace marcelb {
marcelb::Metrics::Metrics(map<string, uint> _counters) {
template<typename K>
Metrics<K>::Metrics() {}
template<typename K>
Metrics<K>::Metrics(map<K, uint64_t> _counters) {
set(_counters);
}
void marcelb::Metrics::clear() {
lock_guard<mutex> _io(io);
template<typename K>
void Metrics<K>::clear() {
unique_lock<shared_mutex> lock(mtx);
counters.clear();
return;
}
vector<string> marcelb::Metrics::keys() {
vector<string> _keys;
for (auto counter : counters) {
template<typename K>
vector<K> Metrics<K>::keys() const {
shared_lock<shared_mutex> lock(mtx);
vector<K> _keys;
for (auto& counter : counters) {
_keys.push_back(counter.first);
}
return _keys;
}
map<string, uint> marcelb::Metrics::get_data() {
return counters;
template<typename K>
map<K, uint64_t> Metrics<K>::get_data() const {
shared_lock<shared_mutex> lock(mtx);
map<K, uint64_t> data;
for (const auto& counter : counters) {
data[counter.first] = counter.second.load();
}
return data;
}
map<string, uint> marcelb::Metrics::get_data_and_clear() {
auto data = counters;
template<typename K>
map<K, uint64_t> Metrics<K>::get_data_and_clear() {
map<K, uint64_t> data;
{
shared_lock<shared_mutex> lock(mtx);
auto data = get_data();
}
clear();
return data;
}
template<typename K>
atomic<uint64_t>& Metrics<K>::operator[](const K& key) {
shared_lock<shared_mutex> lock(mtx);
return counters[key];
}
template<typename K>
Metrics<K>& Metrics<K>::operator++(int n) {
shared_lock<shared_mutex> lock(mtx);
// Increment all counters by n as an example
for (auto& counter : counters) {
counter.second.fetch_add(n, memory_order_relaxed);
}
return *this;
}
template<typename K>
void Metrics<K>::set(map<K, uint64_t> _counters) {
unique_lock<shared_mutex> lock(mtx);
counters.clear();
for (auto& counter : _counters) {
counters[counter.first].store(counter.second);
}
}
template class Metrics<string>;
template class Metrics<uint32_t>;
}

3
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,3 @@
add_executable(metrics_test test.cpp)
target_link_libraries(metrics_test metrics)

BIN
test/test

Binary file not shown.

View File

@ -1,21 +1,54 @@
#include <iostream>
#include <string>
#include <atomic>
using namespace std;
#include "../lib/metrics.hpp"
using namespace marcelb;
int main() {
Metrics metrika;
// atomic<int> a(0);
// a++;
// cout << a << endl;
Metrics<string> metrika;
cout << " access " << metrika["access"]++ << endl;
cout << " access " << metrika["access"]++ << endl;
cout << " error " << metrika["error"] << endl;
cout << " access " << metrika["access"] << endl;
metrika.keys();
// metrika.keys();
cout << " error " << metrika["error"] << endl;
cout << " access " << metrika["access"] << endl;
Metrics<uint32_t> metrika2;
enum keys {
access = 1,
error
};
cout << " access " << metrika2[keys::access]++ << endl;
cout << " access " << metrika2[keys::access]++ << endl;
cout << " error " << metrika2[keys::error] << endl;
cout << " access " << metrika2[keys::access] << endl;
// metrika2.keys();
cout << " error " << metrika2[keys::error] << endl;
cout << " access " << metrika2[keys::access] << endl;
// // init
// Metrics stats;
// // operator [] and increment ++
@ -29,7 +62,7 @@ int main() {
// // reset counters
// stats.clear();
// // set counters
// map<string, uint> MyStats = {{"access", 3},{ "error", 0}};
// map<string, uint64_t> MyStats = {{"access", 3},{ "error", 0}};
// stats.set(MyStats);
// // get and clear all counters
// auto dataWithClear = stats.get_data_and_clear();