Skip to content

Commit

Permalink
Improve knobs and cmdl
Browse files Browse the repository at this point in the history
  • Loading branch information
Force67 committed Oct 25, 2024
1 parent 98c7323 commit e14f502
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 79 deletions.
6 changes: 3 additions & 3 deletions base/command_line.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ i32 CommandLine::FindSwitchIndex(const base::StringRefU8 switch_name) {
return i;
}
}
return -1;
return kNotFoundIndex;
}

base::StringRefU8 CommandLine::ExtractSwitchValue(
Expand All @@ -94,7 +94,7 @@ base::StringRefU8 CommandLine::operator[](const mem_size index) CONST_ND {

base::StringRefU8 CommandLine::at(const mem_size index) {
auto cap = pieces_.size();
if (index > cap || index == -1)
if (index > cap || index == kNotFoundIndex)
return u8"";
const auto& piece = pieces_[index];
return base::StringRefU8(piece.c_str(), piece.length(), true); // No +1 as nterm doesnt count as character
Expand All @@ -112,4 +112,4 @@ xsize CommandLine::FindPositionalArgumentsIndex() {
}
return positional_index;
}
} // namespace base
} // namespace base
5 changes: 3 additions & 2 deletions base/command_line.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,20 @@ class CommandLine {
// simply checks if the command line has exactly these contents, somewhere
bool HasItem(const base::StringRefU8 item_contents);

static constexpr i32 kNotFoundIndex = -1;
// tries to match a switch in the command line, switches can either start with
// - or -- and can contain values.
// if found, returns the index in the pieces_ array.
// if not found, returns -1
i32 FindSwitchIndex(const base::StringRefU8 switch_name);

bool FindSwitch(const base::StringRefU8 switch_name) {
return FindSwitchIndex(switch_name) != -1;
return FindSwitchIndex(switch_name) != kNotFoundIndex;
}

base::StringRefU8 FindSwitchValue(const base::StringRefU8 switch_name) {
i32 res = FindSwitchIndex(switch_name);
if (res == -1)
if (res == kNotFoundIndex)
return u8"";
return CommandLine::ExtractSwitchValue(at(res));
}
Expand Down
17 changes: 9 additions & 8 deletions base/gen_knobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ def generate_init_header(knobs: List[Tuple[str, str, str]], output_file: str):
f.write("#pragma once\n\n")
f.write("#include <base/knob.h>\n\n")
f.write("namespace feature_flags {\n\n")

# Declare extern Knobs
for knob_type, knob_name, _ in knobs:
f.write(f"extern base::Knob<{knob_type}> {knob_name};\n")

f.write("\ninline void InitializeAllKnobs() {\n")
for knob_type, knob_name, initializer in knobs:
if initializer:
f.write(f" {knob_name}.Construct({initializer});\n")
else:
f.write(f" {knob_name}.Construct();\n")
#if initializer:
# f.write(f" {knob_name}.Construct({initializer});\n")
#else:
f.write(f" {knob_name}.Construct();\n")
f.write("}\n\n")

f.write("inline void DestructAllKnobs() {\n")
Expand All @@ -55,7 +55,8 @@ def generate_init_header(knobs: List[Tuple[str, str, str]], output_file: str):
f.write("inline void InitializeAllKnobsAndRegister(KnobEntry (&knob_list)[kKnobCount]) {\n")
f.write(" InitializeAllKnobs();\n")
for i, (_, knob_name, _) in enumerate(knobs):
f.write(f' knob_list[{i}] = KnobEntry{{"{knob_name}", &{knob_name}}};\n')
snake_case = re.sub(r'(?<!^)(?=[A-Z])', '_', knob_name).lower()
f.write(f' knob_list[{i}] = KnobEntry{{"{snake_case}", &{knob_name}}};\n')
f.write("}\n\n")

f.write("} // namespace feature_flags\n")
Expand All @@ -71,4 +72,4 @@ def main():
print(f"Generated {args.output_file} with {len(knobs)} knobs.")

if __name__ == "__main__":
main()
main()
133 changes: 70 additions & 63 deletions base/knob.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,68 +6,75 @@

namespace base {

// Generic Prototype
struct BasicKnob {};

// Just a utility struct for the generated code.
struct KnobEntry {
const char* name;
base::BasicKnob* knob_obj;
};

// Specialization for POD types
template<typename T, bool is_trivial = base::IsTrivial<T>>
struct Knob final : public BasicKnob {
static_assert(is_trivial, "This specialization is for POD types only.");
// POD Ctor
Knob(T val) : data(val) {}
// disable copy/move
Knob(const Knob&) = delete;
Knob(Knob&&) = delete;
// no-op
void Construct() {}
void Destruct() {}

T& value() {
return data; // Direct access since it's POD
}

const T& value() const {
return data; // Direct access since it's POD
}
operator bool() { return data; }

T data{};
};

// Specialization for non-POD types
template <typename T>
struct Knob<T, false> final : public BasicKnob {
using Type = T;

// disable copy/move
Knob(const Knob&) = delete;
Knob(Knob&&) = delete;

template <typename... Args>
void Construct(Args&&... args) {
new (&data_) T(base::forward<Args>(args)...);
}

void Destruct() {
reinterpret_cast<T*>(&data_)->~T();
}

T& value() {
return *reinterpret_cast<T*>(&data_);
}

const T& value() const {
return *reinterpret_cast<const T*>(&data_);
}

private:
alignas(T) byte data_[sizeof(T)]{};
};
// Generic Prototype
struct BasicKnob {};
static_assert(sizeof(BasicKnob) == 1, "BasicKnob should be empty");

// Just a utility struct for the generated code.
struct KnobEntry {
const char* name;
base::BasicKnob* knob_obj;
};

// Usage: global Knob<bool> MyBooleanOption;
// Then run python /equilibrium/base/gen_knobs.py . knobs.h
// It will generate:
// - void InitializeAllKnobs()
// - void DestructAllKnobs()
// and void InitializeAllKnobsAndRegister(KnobEntry (&knob_list)[kKnobCount])
// Names will be convered to snake_case ish for the displaynames.
// We guarantee the data starts at offset 0 from the knob_obj.

// Specialization for POD types
template <typename T, bool is_trivial = base::IsTrivial<T>>
struct Knob final : public BasicKnob {
static_assert(is_trivial, "This specialization is for POD types only.");
// POD Ctor
Knob(T val) : data(val) {}
// disable copy/move
Knob(const Knob&) = delete;
Knob(Knob&&) = delete;
// no-op
void Construct() {}
void Destruct() {}

T& value() {
return data; // Direct access since it's POD
}

const T& value() const {
return data; // Direct access since it's POD
}
operator bool() { return data; }

void set_value(const T val) { data = val; }

T data{};
};
static_assert(sizeof(Knob<bool>) == 1, "Knob<bool> should be 1 byte");

// Specialization for non-POD types
template <typename T>
struct Knob<T, false> final : public BasicKnob {
using Type = T;

// disable copy/move
Knob(const Knob&) = delete;
Knob(Knob&&) = delete;

template <typename... Args>
void Construct(Args&&... args) {
new (&data_) T(base::forward<Args>(args)...);
}

void Destruct() { reinterpret_cast<T*>(&data_)->~T(); }

T& value() { return *reinterpret_cast<T*>(&data_); }

const T& value() const { return *reinterpret_cast<const T*>(&data_); }

private:
alignas(T) byte data_[sizeof(T)]{};
};

} // namespace base
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e14f502

Please sign in to comment.