-
Notifications
You must be signed in to change notification settings - Fork 3
feat: Add context type, value type, and associated builders. #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
40e9f05
1f43c9e
e731ca2
2ad041a
cf7ffb2
4bc1dda
38d5f3e
f844a82
b51e895
0cede01
7f77f5c
e4a5bd7
462b3f8
9df9037
a7c4f6f
6e8ed91
f2aca36
40bd8bc
cd1613f
de249f0
b58cd6d
652f392
e899878
14e4068
a9185e2
59875dd
c266153
0001e83
3622248
d158782
86ff211
b3c68d9
4c06c87
d4e74be
b5d35b4
8b65916
432d6ad
ef898af
f99395a
baf6460
8305d2d
0a4b1ff
5ab874f
70b4bba
3b5a648
c037122
287b094
b982483
48c8adb
5e953c3
4f8c711
5e6f98c
80e17c7
b8490e9
1a7211a
486edeb
c12b34c
024dd4b
a9a0564
7561602
a3d8658
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,13 @@ | ||
| #pragma once | ||
|
|
||
| #include <cstddef> | ||
| #include <ostream> | ||
| #include <string> | ||
| #include <unordered_set> | ||
| #include <vector> | ||
|
|
||
| #include <boost/container_hash/hash.hpp> | ||
|
|
||
| namespace launchdarkly { | ||
|
|
||
| /** | ||
|
|
@@ -28,6 +32,19 @@ namespace launchdarkly { | |
| */ | ||
| class AttributeReference { | ||
| public: | ||
| /** | ||
| * Provides a hashing function for use with unordered sets. | ||
| */ | ||
| struct HashFunction { | ||
| std::size_t operator()(AttributeReference const& ref) const { | ||
| return boost::hash_range(ref.components_.begin(), | ||
| ref.components_.end()); | ||
| } | ||
| }; | ||
|
|
||
| using SetType = std::unordered_set<AttributeReference, | ||
| AttributeReference::HashFunction>; | ||
|
|
||
| /** | ||
| * Get the component of the attribute reference at the specified depth. | ||
| * | ||
|
|
@@ -38,15 +55,15 @@ class AttributeReference { | |
| * @return The component at the specified depth or an empty string if the | ||
| * depth is out of bounds. | ||
| */ | ||
| std::string const& component(size_t depth) const; | ||
| std::string const& component(std::size_t depth) const; | ||
|
|
||
| /** | ||
| * Get the total depth of the reference. | ||
| * | ||
| * For example, depth() on the reference `/a/b/c` would return 3. | ||
| * @return | ||
| */ | ||
| size_t depth() const; | ||
| std::size_t depth() const; | ||
|
|
||
| /** | ||
| * Check if the reference is a "kind" reference. Either `/kind` or `kind`. | ||
|
|
@@ -94,10 +111,34 @@ class AttributeReference { | |
| return os; | ||
| } | ||
|
|
||
| /** | ||
| * Construct an attribute reference from a string. | ||
| * @param ref_str The string to make an attribute reference from. | ||
| */ | ||
| AttributeReference(std::string ref_str); | ||
|
|
||
| /** | ||
| * Construct an attribute reference from a constant string. | ||
| * @param ref_str The string to make an attribute reference from. | ||
| */ | ||
| AttributeReference(char const* ref_str); | ||
|
|
||
| bool operator==(AttributeReference const& other) const { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May as well work with an ordered set as well. |
||
| return components_ == other.components_; | ||
| } | ||
|
|
||
| bool operator!=(AttributeReference const& other) const { | ||
| return !(*this == other); | ||
| } | ||
|
|
||
| bool operator<(AttributeReference const& rhs) const { | ||
| return components_ < rhs.components_; | ||
| } | ||
|
|
||
| private: | ||
| AttributeReference(std::string str, bool is_literal); | ||
|
|
||
| bool valid_; | ||
| bool valid_ = false; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: can this be initialized in the constructor instead? (or rather - is there a reason to do it here)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know that one is better than the other. It is just easier to make sure that it is initialized regardless of what constructor is used, and it doesn't really cost anything. |
||
|
|
||
| std::string redaction_name_; | ||
| std::vector<std::string> components_; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| #pragma once | ||
|
|
||
| #include <string> | ||
| #include <unordered_set> | ||
|
|
||
| #include "attribute_reference.hpp" | ||
| #include "value.hpp" | ||
|
|
||
| namespace launchdarkly { | ||
|
|
||
| /** | ||
| * A collection of attributes that can be present within a context. | ||
| * A multi-context has multiple sets of attributes keyed by their "kind". | ||
| */ | ||
| class Attributes { | ||
| public: | ||
| /** | ||
| * Get the key for the context. | ||
| * @return A reference to the context key. | ||
| */ | ||
| std::string const& key() const; | ||
|
|
||
| /** | ||
| * Get the name for the context. | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe I should use a Value here. It is actually kind of convenient. :-P |
||
| * | ||
| * @return A reference to the context name, or an empty string if no name | ||
| * is set. | ||
| */ | ||
| std::string const& name() const; | ||
|
|
||
| /** | ||
| * Is the context anonymous or not. Defaults to false. | ||
| * @return True if the context is anonymous. | ||
| */ | ||
| bool anonymous() const; | ||
|
|
||
| /** | ||
| * Get a set of the private attributes for the context. | ||
| * @return The set of private attributes for the context. | ||
| */ | ||
| AttributeReference::SetType const& private_attributes() const { | ||
| return private_attributes_; | ||
| } | ||
|
|
||
| /** | ||
| * Gets the item by the specified attribute reference, or returns a null | ||
| * Value. | ||
| * @param ref The reference to get an attribute by. | ||
| * @return A Value containing the requested field, or a Value representing | ||
| * null. | ||
| */ | ||
| launchdarkly::Value const& get( | ||
| launchdarkly::AttributeReference const& ref) const { | ||
| if (!ref.valid()) { | ||
| // Cannot index by invalid references. | ||
| return launchdarkly::Value::null(); | ||
| } | ||
| if (ref.is_kind()) { | ||
| // Cannot access kind. | ||
| return launchdarkly::Value::null(); | ||
| } | ||
|
|
||
| if (ref.depth() == 1) { | ||
| // Handle built-in attributes. | ||
| if (ref.component(0) == "key") { | ||
| return key_; | ||
| } | ||
| if (ref.component(0) == "name") { | ||
| return name_; | ||
| } | ||
| if (ref.component(0) == "anonymous") { | ||
| return anonymous_; | ||
| } | ||
| } | ||
|
|
||
| launchdarkly::Value const* node = &custom_attributes_; | ||
| bool found = true; | ||
| for (size_t index = 0; index < ref.depth(); index++) { | ||
| auto const& component = ref.component(index); | ||
| if (node->is_object()) { | ||
| auto const& map = node->as_object(); | ||
| if (auto search = map.find(component); search != map.end()) { | ||
| node = &search->second; | ||
| } else { | ||
| found = false; | ||
| break; | ||
| } | ||
| } else { | ||
| found = false; | ||
| } | ||
| } | ||
| if (!found) { | ||
| return launchdarkly::Value::null(); | ||
| } | ||
| return *node; | ||
| } | ||
|
|
||
| /** | ||
| * Construct a set of attributes. This is used internally by the SDK | ||
| * but is not intended to used by consumers of the SDK. | ||
| * | ||
| * @param key The key for the context. | ||
| * @param name The name of the context. | ||
| * @param anonymous If the context is anonymous. | ||
| * @param attributes Additional attributes for the context. | ||
| * @param private_attributes A list of attributes that should be private. | ||
| */ | ||
| Attributes(std::string key, | ||
| std::optional<std::string> name, | ||
| bool anonymous, | ||
| launchdarkly::Value attributes, | ||
| AttributeReference::SetType private_attributes = | ||
| AttributeReference::SetType()) | ||
| : key_(std::move(key)), | ||
| name_(std::move(name)), | ||
| anonymous_(anonymous), | ||
| custom_attributes_(std::move(attributes)), | ||
| private_attributes_(std::move(private_attributes)) {} | ||
|
|
||
| friend std::ostream& operator<<(std::ostream& out, | ||
| Attributes const& attrs) { | ||
| out << "{key: " << attrs.key_ << ", " | ||
| << " name: " << attrs.name_ << " anonymous: " << attrs.anonymous_ | ||
| << " private: ["; | ||
| bool first = true; | ||
| for (auto const& private_attribute : attrs.private_attributes_) { | ||
| if (first) { | ||
| first = false; | ||
| } else { | ||
| out << ", "; | ||
| } | ||
| out << private_attribute; | ||
| } | ||
| out << "] " | ||
| << " custom: " << attrs.custom_attributes_ << "}"; | ||
|
|
||
| return out; | ||
| } | ||
|
|
||
| private: | ||
| // Built-in attributes. | ||
| launchdarkly::Value key_; | ||
| launchdarkly::Value name_; | ||
| launchdarkly::Value anonymous_; | ||
| AttributeReference::SetType private_attributes_; | ||
|
|
||
| launchdarkly::Value custom_attributes_; | ||
|
|
||
| // Kinds are contained at the context level, not inside attributes. | ||
| }; | ||
| } // namespace launchdarkly | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hashing to work with an unordered set.