Skip to content

Commit b6edb69

Browse files
authored
feat: Add context type, value type, and associated builders. (#5)
1 parent 10763e7 commit b6edb69

19 files changed

+2003
-9
lines changed

libs/common/CMakeLists.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@ if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
2121
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
2222
endif ()
2323

24-
#set(CMAKE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
25-
#set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_FILES})
26-
2724
# Needed to fetch external dependencies.
2825
include(FetchContent)
2926

27+
set(Boost_USE_STATIC_LIBS OFF)
28+
set(Boost_USE_MULTITHREADED ON)
29+
set(Boost_USE_STATIC_RUNTIME OFF)
30+
find_package(Boost 1.80 REQUIRED)
31+
message(STATUS "LaunchDarkly: using Boost v${Boost_VERSION}")
32+
3033
# Add main SDK sources.
3134
add_subdirectory(src)
3235

libs/common/include/attribute_reference.hpp

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
#pragma once
22

3+
#include <cstddef>
34
#include <ostream>
45
#include <string>
6+
#include <unordered_set>
57
#include <vector>
68

9+
#include <boost/container_hash/hash.hpp>
10+
711
namespace launchdarkly {
812

913
/**
@@ -28,6 +32,19 @@ namespace launchdarkly {
2832
*/
2933
class AttributeReference {
3034
public:
35+
/**
36+
* Provides a hashing function for use with unordered sets.
37+
*/
38+
struct HashFunction {
39+
std::size_t operator()(AttributeReference const& ref) const {
40+
return boost::hash_range(ref.components_.begin(),
41+
ref.components_.end());
42+
}
43+
};
44+
45+
using SetType = std::unordered_set<AttributeReference,
46+
AttributeReference::HashFunction>;
47+
3148
/**
3249
* Get the component of the attribute reference at the specified depth.
3350
*
@@ -38,15 +55,15 @@ class AttributeReference {
3855
* @return The component at the specified depth or an empty string if the
3956
* depth is out of bounds.
4057
*/
41-
std::string const& component(size_t depth) const;
58+
std::string const& component(std::size_t depth) const;
4259

4360
/**
4461
* Get the total depth of the reference.
4562
*
4663
* For example, depth() on the reference `/a/b/c` would return 3.
4764
* @return
4865
*/
49-
size_t depth() const;
66+
std::size_t depth() const;
5067

5168
/**
5269
* Check if the reference is a "kind" reference. Either `/kind` or `kind`.
@@ -94,10 +111,34 @@ class AttributeReference {
94111
return os;
95112
}
96113

114+
/**
115+
* Construct an attribute reference from a string.
116+
* @param ref_str The string to make an attribute reference from.
117+
*/
118+
AttributeReference(std::string ref_str);
119+
120+
/**
121+
* Construct an attribute reference from a constant string.
122+
* @param ref_str The string to make an attribute reference from.
123+
*/
124+
AttributeReference(char const* ref_str);
125+
126+
bool operator==(AttributeReference const& other) const {
127+
return components_ == other.components_;
128+
}
129+
130+
bool operator!=(AttributeReference const& other) const {
131+
return !(*this == other);
132+
}
133+
134+
bool operator<(AttributeReference const& rhs) const {
135+
return components_ < rhs.components_;
136+
}
137+
97138
private:
98139
AttributeReference(std::string str, bool is_literal);
99140

100-
bool valid_;
141+
bool valid_ = false;
101142

102143
std::string redaction_name_;
103144
std::vector<std::string> components_;

libs/common/include/attributes.hpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <unordered_set>
5+
6+
#include "attribute_reference.hpp"
7+
#include "value.hpp"
8+
9+
namespace launchdarkly {
10+
11+
/**
12+
* A collection of attributes that can be present within a context.
13+
* A multi-context has multiple sets of attributes keyed by their "kind".
14+
*/
15+
class Attributes {
16+
public:
17+
/**
18+
* Get the key for the context.
19+
* @return A reference to the context key.
20+
*/
21+
std::string const& key() const;
22+
23+
/**
24+
* Get the name for the context.
25+
*
26+
* @return A reference to the context name, or an empty string if no name
27+
* is set.
28+
*/
29+
std::string const& name() const;
30+
31+
/**
32+
* Is the context anonymous or not. Defaults to false.
33+
* @return True if the context is anonymous.
34+
*/
35+
bool anonymous() const;
36+
37+
/**
38+
* Get a set of the private attributes for the context.
39+
* @return The set of private attributes for the context.
40+
*/
41+
AttributeReference::SetType const& private_attributes() const {
42+
return private_attributes_;
43+
}
44+
45+
/**
46+
* Gets the item by the specified attribute reference, or returns a null
47+
* Value.
48+
* @param ref The reference to get an attribute by.
49+
* @return A Value containing the requested field, or a Value representing
50+
* null.
51+
*/
52+
launchdarkly::Value const& get(
53+
launchdarkly::AttributeReference const& ref) const {
54+
if (!ref.valid()) {
55+
// Cannot index by invalid references.
56+
return launchdarkly::Value::null();
57+
}
58+
if (ref.is_kind()) {
59+
// Cannot access kind.
60+
return launchdarkly::Value::null();
61+
}
62+
63+
if (ref.depth() == 1) {
64+
// Handle built-in attributes.
65+
if (ref.component(0) == "key") {
66+
return key_;
67+
}
68+
if (ref.component(0) == "name") {
69+
return name_;
70+
}
71+
if (ref.component(0) == "anonymous") {
72+
return anonymous_;
73+
}
74+
}
75+
76+
launchdarkly::Value const* node = &custom_attributes_;
77+
bool found = true;
78+
for (size_t index = 0; index < ref.depth(); index++) {
79+
auto const& component = ref.component(index);
80+
if (node->is_object()) {
81+
auto const& map = node->as_object();
82+
if (auto search = map.find(component); search != map.end()) {
83+
node = &search->second;
84+
} else {
85+
found = false;
86+
break;
87+
}
88+
} else {
89+
found = false;
90+
}
91+
}
92+
if (!found) {
93+
return launchdarkly::Value::null();
94+
}
95+
return *node;
96+
}
97+
98+
/**
99+
* Construct a set of attributes. This is used internally by the SDK
100+
* but is not intended to used by consumers of the SDK.
101+
*
102+
* @param key The key for the context.
103+
* @param name The name of the context.
104+
* @param anonymous If the context is anonymous.
105+
* @param attributes Additional attributes for the context.
106+
* @param private_attributes A list of attributes that should be private.
107+
*/
108+
Attributes(std::string key,
109+
std::optional<std::string> name,
110+
bool anonymous,
111+
launchdarkly::Value attributes,
112+
AttributeReference::SetType private_attributes =
113+
AttributeReference::SetType())
114+
: key_(std::move(key)),
115+
name_(std::move(name)),
116+
anonymous_(anonymous),
117+
custom_attributes_(std::move(attributes)),
118+
private_attributes_(std::move(private_attributes)) {}
119+
120+
friend std::ostream& operator<<(std::ostream& out,
121+
Attributes const& attrs) {
122+
out << "{key: " << attrs.key_ << ", "
123+
<< " name: " << attrs.name_ << " anonymous: " << attrs.anonymous_
124+
<< " private: [";
125+
bool first = true;
126+
for (auto const& private_attribute : attrs.private_attributes_) {
127+
if (first) {
128+
first = false;
129+
} else {
130+
out << ", ";
131+
}
132+
out << private_attribute;
133+
}
134+
out << "] "
135+
<< " custom: " << attrs.custom_attributes_ << "}";
136+
137+
return out;
138+
}
139+
140+
private:
141+
// Built-in attributes.
142+
launchdarkly::Value key_;
143+
launchdarkly::Value name_;
144+
launchdarkly::Value anonymous_;
145+
AttributeReference::SetType private_attributes_;
146+
147+
launchdarkly::Value custom_attributes_;
148+
149+
// Kinds are contained at the context level, not inside attributes.
150+
};
151+
} // namespace launchdarkly

0 commit comments

Comments
 (0)