Created
September 19, 2018 14:57
-
-
Save arrieta/3eb1eeca3cb212e6e77569fdf33fea6d to your computer and use it in GitHub Desktop.
C++ Translation of Go Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// I am interested in practical comparisons between C++ and Go. To this end, I | |
// find "good" Go code (by some definition of "good") and translate it into C++. | |
// | |
// It is mostly unimportant what the code does (in fact, it does not do anything | |
// at all). What matters is to attempt to capture the same API and semantics. | |
// | |
// This file implements a class called "Awareness" found in the hashicorp repo: | |
// | |
// https://github.com/hashicorp/memberlist/blob/master/awareness.go | |
// | |
#include <mutex> | |
#include <shared_mutex> | |
#include <string> | |
#include <vector> | |
// Some function that came from another Go module. | |
extern void SetGauge(const std::vector<std::string>&, int); | |
class Awareness { | |
public: | |
explicit Awareness(int max) : m_score(0), m_max(max) {} | |
void ApplyDelta(int delta) { | |
int initial_score = 0; | |
int final_score = 0; | |
{ | |
// A unique lock is exclusive; only one thread can acquire it (normally | |
// used for writing). | |
std::unique_lock<std::shared_mutex> lock(m_rwmux); | |
initial_score = m_score; | |
m_score += delta; | |
if (m_score < 0) { | |
m_score = 0; | |
} else if (m_score > m_max - 1) { | |
m_score = m_max - 1; | |
} | |
final_score = m_score; | |
} // at this point the unique lock has been released | |
// This call is placed outside the unique lock. | |
if (initial_score != final_score) { | |
SetGauge({"memberlist", "health", "score"}, final_score); | |
} | |
} | |
int GetHealthScore() const { | |
// A shared lock is non-exclusive; several threads can simultaneously | |
// acquire it (normally used for reading). | |
std::shared_lock<std::shared_mutex> lock(m_rwmux); | |
return m_score; | |
} | |
int ScaleTimeout(int timeout) const { | |
auto score = GetHealthScore(); // thread-safe access | |
return timeout * (score + 1); | |
} | |
private: | |
int m_score; | |
int m_max; | |
// Serialize R/W access | |
mutable std::shared_mutex m_rwmux; | |
}; |
// In practice, I would split the interface from the implementation. This would
// be the header file "awareness.hpp".
#pragma once
#include <shared_mutex>
class Awareness {
public:
explicit Awareness(int max);
void ApplyDelta(int delta);
int GetHealthScore() const;
int ScaleTimeout(int timeout) const;
private:
int m_score;
int m_max;
// Serialize R/W access
mutable std::shared_mutex m_rwmux;
};
// This would be the implementation file "awareness.cpp"
#include "awareness.hpp"
#include <mutex> // for std::unique_lock
#include "metrics.hpp" // for SetGauge
Awareness::Awareness(int max) : m_score(0), m_max(max) {}
void Awareness::ApplyDelta(int delta) {
int initial_score = 0;
int final_score = 0;
{
// A unique lock is exclusive; only one thread can acquire it (normally
// used for writing).
std::unique_lock<std::shared_mutex> lock(m_rwmux);
initial_score = m_score;
m_score += delta;
if (m_score < 0) {
m_score = 0;
} else if (m_score > m_max - 1) {
m_score = m_max - 1;
}
final_score = m_score;
} // at this point the unique lock has been released
// This call is placed outside the unique lock.
if (initial_score != final_score) {
metrics::SetGauge({"memberlist", "health", "score"}, final_score);
}
}
int Awareness::GetHealthScore() const {
// A shared lock is non-exclusive; several threads can simultaneously
// acquire it (normally used for reading).
std::shared_lock<std::shared_mutex> lock(m_rwmux);
return m_score;
}
int Awareness::ScaleTimeout(int timeout) const {
auto score = GetHealthScore(); // thread-safe access
return timeout * (score + 1);
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For reference, this is the original Go code: