mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
base support for differentiated record field accessors
This commit is contained in:
parent
0118b6ee38
commit
e363bab55f
2 changed files with 109 additions and 15 deletions
|
@ -344,8 +344,8 @@ Connection* NetSessions::FindConnection(Val* v)
|
|||
const IPAddr& orig_addr = vl->GetFieldAs<AddrVal>(orig_h);
|
||||
const IPAddr& resp_addr = vl->GetFieldAs<AddrVal>(resp_h);
|
||||
|
||||
const PortVal* orig_portv = vl->GetFieldAs<PortVal>(orig_p);
|
||||
const PortVal* resp_portv = vl->GetFieldAs<PortVal>(resp_p);
|
||||
auto orig_portv = vl->GetFieldAs<PortVal>(orig_p);
|
||||
auto resp_portv = vl->GetFieldAs<PortVal>(resp_p);
|
||||
|
||||
ConnID id;
|
||||
|
||||
|
|
118
src/Val.h
118
src/Val.h
|
@ -73,6 +73,7 @@ class EnumVal;
|
|||
class OpaqueVal;
|
||||
class VectorVal;
|
||||
class TableEntryVal;
|
||||
class TypeVal;
|
||||
|
||||
using AddrValPtr = IntrusivePtr<AddrVal>;
|
||||
using EnumValPtr = IntrusivePtr<EnumVal>;
|
||||
|
@ -446,14 +447,19 @@ public:
|
|||
// Returns a masked port number
|
||||
static uint32_t Mask(uint32_t port_num, TransportProto port_type);
|
||||
|
||||
const PortVal* Get() const { return AsPortVal(); }
|
||||
|
||||
protected:
|
||||
friend class ValManager;
|
||||
PortVal(uint32_t p);
|
||||
|
||||
void ValDescribe(ODesc* d) const override;
|
||||
ValPtr DoClone(CloneState* state) override;
|
||||
|
||||
private:
|
||||
// This method is just here to trick the interface in
|
||||
// `RecordVal::GetFieldAs` into returning the right type.
|
||||
// It shouldn't actually be used for anything.
|
||||
friend class RecordVal;
|
||||
PortValPtr Get() { return {NewRef{}, this}; }
|
||||
};
|
||||
|
||||
class AddrVal final : public Val {
|
||||
|
@ -996,6 +1002,39 @@ private:
|
|||
PDict<TableEntryVal>* table_val;
|
||||
};
|
||||
|
||||
// This would be way easier with is_convertible_v, but sadly that won't
|
||||
// work here because Obj has deleted copy constructors (and for good
|
||||
// reason). Instead we make up our own type trait here that basically
|
||||
// combines a bunch of is_same traits into a single trait to make life
|
||||
// easier in the definitions of GetFieldAs().
|
||||
template <typename T>
|
||||
struct is_zeek_val
|
||||
{
|
||||
static const bool value = std::disjunction_v<
|
||||
std::is_same<AddrVal, T>,
|
||||
std::is_same<BoolVal, T>,
|
||||
std::is_same<CountVal, T>,
|
||||
std::is_same<DoubleVal, T>,
|
||||
std::is_same<EnumVal, T>,
|
||||
std::is_same<FileVal, T>,
|
||||
std::is_same<FuncVal, T>,
|
||||
std::is_same<IntVal, T>,
|
||||
std::is_same<IntervalVal, T>,
|
||||
std::is_same<ListVal, T>,
|
||||
std::is_same<OpaqueVal, T>,
|
||||
std::is_same<PatternVal, T>,
|
||||
std::is_same<PortVal, T>,
|
||||
std::is_same<RecordVal, T>,
|
||||
std::is_same<StringVal, T>,
|
||||
std::is_same<SubNetVal, T>,
|
||||
std::is_same<TableVal, T>,
|
||||
std::is_same<TimeVal, T>,
|
||||
std::is_same<TypeVal, T>,
|
||||
std::is_same<VectorVal, T>>;
|
||||
};
|
||||
template <typename T>
|
||||
inline constexpr bool is_zeek_val_v = is_zeek_val<T>::value;
|
||||
|
||||
class RecordVal final : public Val, public notifier::detail::Modifiable {
|
||||
public:
|
||||
explicit RecordVal(RecordTypePtr t, bool init_fields = true);
|
||||
|
@ -1148,22 +1187,77 @@ public:
|
|||
|
||||
// The following return the given field converted to a particular
|
||||
// underlying value. We provide these to enable efficient
|
||||
// access to record fields (without requiring an intermediary Val)
|
||||
// if we change the underlying representation of records.
|
||||
template <typename T>
|
||||
// access to record fields (without requiring an intermediary Val).
|
||||
// It is up to the caller to ensure that the field exists in the
|
||||
// record (using HasField(), if necessary).
|
||||
template <typename T,
|
||||
typename std::enable_if_t<is_zeek_val_v<T>, bool> = true>
|
||||
auto GetFieldAs(int field) const -> std::invoke_result_t<decltype(&T::Get), T>
|
||||
{
|
||||
auto field_ptr = GetField(field);
|
||||
auto field_val_ptr = static_cast<T*>(field_ptr.get());
|
||||
return field_val_ptr->Get();
|
||||
if constexpr ( std::is_same_v<T, BoolVal> ||
|
||||
std::is_same_v<T, IntVal> ||
|
||||
std::is_same_v<T, EnumVal> )
|
||||
return record_val->at(field).int_val;
|
||||
else if constexpr ( std::is_same_v<T, CountVal> )
|
||||
return record_val->at(field).uint_val;
|
||||
else if constexpr ( std::is_same_v<T, DoubleVal> ||
|
||||
std::is_same_v<T, TimeVal> ||
|
||||
std::is_same_v<T, IntervalVal> )
|
||||
return record_val->at(field).double_val;
|
||||
else if constexpr ( std::is_same_v<T, PortVal> )
|
||||
return val_mgr->Port(record_val->at(field).uint_val);
|
||||
else if constexpr ( std::is_same_v<T, StringVal> )
|
||||
return record_val->at(field).string_val->Get();
|
||||
else if constexpr ( std::is_same_v<T, AddrVal> )
|
||||
return record_val->at(field).addr_val->Get();
|
||||
else if constexpr ( std::is_same_v<T, SubNetVal> )
|
||||
return record_val->at(field).subnet_val->Get();
|
||||
else if constexpr ( std::is_same_v<T, File> )
|
||||
return *(record_val->at(field).file_val);
|
||||
else if constexpr ( std::is_same_v<T, Func> )
|
||||
return *(record_val->at(field).func_val);
|
||||
else if constexpr ( std::is_same_v<T, PatternVal> )
|
||||
return record_val->at(field).re_val->Get();
|
||||
else if constexpr ( std::is_same_v<T, RecordVal> )
|
||||
return record_val->at(field).record_val;
|
||||
else if constexpr ( std::is_same_v<T, VectorVal> )
|
||||
return record_val->at(field).vector_val;
|
||||
else if constexpr ( std::is_same_v<T, TableVal> )
|
||||
return record_val->at(field).table_val->Get();
|
||||
else
|
||||
{
|
||||
// TODO: error here, although because of the
|
||||
// type trait it really shouldn't ever get here.
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename std::enable_if_t<!is_zeek_val_v<T>, bool> = true>
|
||||
T GetFieldAs(int field) const
|
||||
{
|
||||
if constexpr ( std::is_integral_v<T> && std::is_signed_v<T> )
|
||||
return record_val->at(field).int_val;
|
||||
else if constexpr ( std::is_integral_v<T> &&
|
||||
std::is_unsigned_v<T> )
|
||||
return record_val->at(field).uint_val;
|
||||
else if constexpr ( std::is_floating_point_v<T> )
|
||||
return record_val->at(field).double_val;
|
||||
|
||||
// Could add other types here using type traits,
|
||||
// such as is_same_v<T, std::string>, etc.
|
||||
|
||||
return T{};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto GetFieldAs(const char* field) const -> std::invoke_result_t<decltype(&T::Get), T>
|
||||
auto GetFieldAs(const char* field) const
|
||||
{
|
||||
auto field_ptr = GetField(field);
|
||||
auto field_val_ptr = static_cast<T*>(field_ptr.get());
|
||||
return field_val_ptr->Get();
|
||||
int idx = GetType()->AsRecordType()->FieldOffset(field);
|
||||
|
||||
if ( idx < 0 )
|
||||
reporter->InternalError("missing record field: %s", field);
|
||||
|
||||
return GetFieldAs<T>(idx);
|
||||
}
|
||||
|
||||
void Describe(ODesc* d) const override;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue