// See the file "COPYING" in the main distribution directory for copyright. #ifndef val_h #define val_h // BRO values. #include #include #include "net_util.h" #include "Type.h" #include "Dict.h" #include "CompHash.h" #include "BroString.h" #include "Attr.h" #include "Timer.h" #include "ID.h" #include "Scope.h" #include "StateAccess.h" #include "IPAddr.h" class Val; class Func; class BroFile; class RE_Matcher; class PrefixTable; class SerialInfo; class PortVal; class AddrVal; class SubNetVal; class IntervalVal; class PatternVal; class TableVal; class RecordVal; class ListVal; class StringVal; class EnumVal; class MutableVal; class StateAccess; class VectorVal; class TableEntryVal; declare(PDict,TableEntryVal); typedef union { // Used for bool, int, enum. bro_int_t int_val; // Used for count, counter, port, subnet. bro_uint_t uint_val; // Used for addr IPAddr* addr_val; // Used for subnet IPPrefix* subnet_val; // Used for double, time, interval. double double_val; BroString* string_val; Func* func_val; BroFile* file_val; RE_Matcher* re_val; PDict(TableEntryVal)* table_val; val_list* val_list_val; vector* vector_val; } BroValUnion; class Val : public BroObj { public: Val(bool b, TypeTag t) { val.int_val = b; type = base_type(t); #ifdef DEBUG bound_id = 0; #endif } Val(int32 i, TypeTag t) { val.int_val = bro_int_t(i); type = base_type(t); #ifdef DEBUG bound_id = 0; #endif } Val(uint32 u, TypeTag t) { val.uint_val = bro_uint_t(u); type = base_type(t); #ifdef DEBUG bound_id = 0; #endif } Val(int64 i, TypeTag t) { val.int_val = i; type = base_type(t); #ifdef DEBUG bound_id = 0; #endif } Val(uint64 u, TypeTag t) { val.uint_val = u; type = base_type(t); #ifdef DEBUG bound_id = 0; #endif } Val(double d, TypeTag t) { val.double_val = d; type = base_type(t); #ifdef DEBUG bound_id = 0; #endif } Val(Func* f); // Note, will unref 'f' when it's done, closing it unless // class has ref'd it. Val(BroFile* f); Val(BroType* t, bool type_type) // Extra arg to differentiate from protected version. { type = new TypeType(t->Ref()); #ifdef DEBUG bound_id = 0; #endif } Val() { val.int_val = 0; type = base_type(TYPE_ERROR); #ifdef DEBUG bound_id = 0; #endif } virtual ~Val(); Val* Ref() { ::Ref(this); return this; } virtual Val* Clone() const; int IsZero() const; int IsOne() const; bro_int_t InternalInt() const; bro_uint_t InternalUnsigned() const; double InternalDouble() const; bro_int_t CoerceToInt() const; bro_uint_t CoerceToUnsigned() const; double CoerceToDouble() const; // Returns a new Val with the "size" of this Val. What constitutes // size depends on the Val's type. virtual Val* SizeVal() const; // Bytes in total value object. virtual unsigned int MemoryAllocation() const; // Add this value to the given value (if appropriate). // Returns true if succcessful. is_first_init is true only if // this is the *first* initialization of the value, not // if it's a subsequent += initialization. virtual int AddTo(Val* v, int is_first_init) const; // Remove this value from the given value (if appropriate). virtual int RemoveFrom(Val* v) const; BroType* Type() { return type; } const BroType* Type() const { return type; } #define CONST_ACCESSOR(tag, ctype, accessor, name) \ const ctype name() const \ { \ CHECK_TAG(type->Tag(), tag, "Val::CONST_ACCESSOR", type_name) \ return val.accessor; \ } // Needed for g++ 4.3's pickiness. #define CONST_ACCESSOR2(tag, ctype, accessor, name) \ ctype name() const \ { \ CHECK_TAG(type->Tag(), tag, "Val::CONST_ACCESSOR", type_name) \ return val.accessor; \ } CONST_ACCESSOR2(TYPE_BOOL, bool, int_val, AsBool) CONST_ACCESSOR2(TYPE_INT, bro_int_t, int_val, AsInt) CONST_ACCESSOR2(TYPE_COUNT, bro_uint_t, uint_val, AsCount) CONST_ACCESSOR2(TYPE_COUNTER, bro_uint_t, uint_val, AsCounter) CONST_ACCESSOR2(TYPE_DOUBLE, double, double_val, AsDouble) CONST_ACCESSOR2(TYPE_TIME, double, double_val, AsTime) CONST_ACCESSOR2(TYPE_INTERVAL, double, double_val, AsInterval) CONST_ACCESSOR2(TYPE_ENUM, int, int_val, AsEnum) CONST_ACCESSOR(TYPE_STRING, BroString*, string_val, AsString) CONST_ACCESSOR(TYPE_FUNC, Func*, func_val, AsFunc) CONST_ACCESSOR(TYPE_TABLE, PDict(TableEntryVal)*, table_val, AsTable) CONST_ACCESSOR(TYPE_RECORD, val_list*, val_list_val, AsRecord) CONST_ACCESSOR(TYPE_FILE, BroFile*, file_val, AsFile) CONST_ACCESSOR(TYPE_PATTERN, RE_Matcher*, re_val, AsPattern) CONST_ACCESSOR(TYPE_VECTOR, vector*, vector_val, AsVector) const IPPrefix& AsSubNet() const { CHECK_TAG(type->Tag(), TYPE_SUBNET, "Val::SubNet", type_name) return *val.subnet_val; } BroType* AsType() const { CHECK_TAG(type->Tag(), TYPE_TYPE, "Val::Type", type_name) return type; } const IPAddr& AsAddr() const { if ( type->Tag() != TYPE_ADDR ) BadTag("Val::AsAddr", type_name(type->Tag())); return *val.addr_val; } #define ACCESSOR(tag, ctype, accessor, name) \ ctype name() \ { \ CHECK_TAG(type->Tag(), tag, "Val::ACCESSOR", type_name) \ return val.accessor; \ } // Accessors for mutable values are called AsNonConst* and // are protected to avoid external state changes. // ACCESSOR(TYPE_STRING, BroString*, string_val, AsString) ACCESSOR(TYPE_FUNC, Func*, func_val, AsFunc) ACCESSOR(TYPE_FILE, BroFile*, file_val, AsFile) ACCESSOR(TYPE_PATTERN, RE_Matcher*, re_val, AsPattern) ACCESSOR(TYPE_VECTOR, vector*, vector_val, AsVector) const IPPrefix& AsSubNet() { CHECK_TAG(type->Tag(), TYPE_SUBNET, "Val::SubNet", type_name) return *val.subnet_val; } const IPAddr& AsAddr() { if ( type->Tag() != TYPE_ADDR ) BadTag("Val::AsAddr", type_name(type->Tag())); return *val.addr_val; } // Gives fast access to the bits of something that is one of // bool, int, count, or counter. bro_int_t ForceAsInt() const { return val.int_val; } bro_uint_t ForceAsUInt() const { return val.uint_val; } #define CONVERTER(tag, ctype, name) \ ctype name() \ { \ CHECK_TAG(type->Tag(), tag, "Val::CONVERTER", type_name) \ return (ctype)(this); \ } CONVERTER(TYPE_PATTERN, PatternVal*, AsPatternVal) CONVERTER(TYPE_PORT, PortVal*, AsPortVal) CONVERTER(TYPE_SUBNET, SubNetVal*, AsSubNetVal) CONVERTER(TYPE_ADDR, AddrVal*, AsAddrVal) CONVERTER(TYPE_TABLE, TableVal*, AsTableVal) CONVERTER(TYPE_RECORD, RecordVal*, AsRecordVal) CONVERTER(TYPE_LIST, ListVal*, AsListVal) CONVERTER(TYPE_STRING, StringVal*, AsStringVal) CONVERTER(TYPE_VECTOR, VectorVal*, AsVectorVal) CONVERTER(TYPE_ENUM, EnumVal*, AsEnumVal) #define CONST_CONVERTER(tag, ctype, name) \ const ctype name() const \ { \ CHECK_TAG(type->Tag(), tag, "Val::CONVERTER", type_name) \ return (const ctype)(this); \ } CONST_CONVERTER(TYPE_PATTERN, PatternVal*, AsPatternVal) CONST_CONVERTER(TYPE_PORT, PortVal*, AsPortVal) CONST_CONVERTER(TYPE_SUBNET, SubNetVal*, AsSubNetVal) CONST_CONVERTER(TYPE_ADDR, AddrVal*, AsAddrVal) CONST_CONVERTER(TYPE_TABLE, TableVal*, AsTableVal) CONST_CONVERTER(TYPE_RECORD, RecordVal*, AsRecordVal) CONST_CONVERTER(TYPE_LIST, ListVal*, AsListVal) CONST_CONVERTER(TYPE_STRING, StringVal*, AsStringVal) CONST_CONVERTER(TYPE_VECTOR, VectorVal*, AsVectorVal) bool IsMutableVal() const { return IsMutable(type->Tag()); } const MutableVal* AsMutableVal() const { if ( ! IsMutableVal() ) BadTag("Val::AsMutableVal", type_name(type->Tag())); return (MutableVal*) this; } MutableVal* AsMutableVal() { if ( ! IsMutableVal() ) BadTag("Val::AsMutableVal", type_name(type->Tag())); return (MutableVal*) this; } void Describe(ODesc* d) const; virtual void DescribeReST(ODesc* d) const; bool Serialize(SerialInfo* info) const; static Val* Unserialize(UnserialInfo* info, TypeTag type = TYPE_ANY) { return Unserialize(info, type, 0); } static Val* Unserialize(UnserialInfo* info, const BroType* exact_type) { return Unserialize(info, exact_type->Tag(), exact_type); } DECLARE_SERIAL(Val); #ifdef DEBUG // For debugging, we keep a reference to the global ID to which a // value has been bound *last*. ID* GetID() const { return bound_id ? global_scope()->Lookup(bound_id) : 0; } void SetID(ID* id) { delete [] bound_id; bound_id = id ? copy_string(id->Name()) : 0; } #endif protected: Val(BroString* s, TypeTag t) { val.string_val = s; type = base_type(t); #ifdef DEBUG bound_id = 0; #endif } virtual void ValDescribe(ODesc* d) const; virtual void ValDescribeReST(ODesc* d) const; Val(TypeTag t) { type = base_type(t); #ifdef DEBUG bound_id = 0; #endif } Val(BroType* t) { type = t->Ref(); #ifdef DEBUG bound_id = 0; #endif } ACCESSOR(TYPE_TABLE, PDict(TableEntryVal)*, table_val, AsNonConstTable) ACCESSOR(TYPE_RECORD, val_list*, val_list_val, AsNonConstRecord) // Just an internal helper. static Val* Unserialize(UnserialInfo* info, TypeTag type, const BroType* exact_type); BroValUnion val; BroType* type; #ifdef DEBUG // For debugging, we keep the name of the ID to which a Val is bound. const char* bound_id; #endif }; class MutableVal : public Val { public: // Each MutableVal gets a globally unique ID that can be used to // reference it no matter if it's directly bound to any user-visible // ID. This ID is inserted into the global namespace. ID* UniqueID() const { return id ? id : Bind(); } // Returns true if we've already generated a unique ID. bool HasUniqueID() const { return id; } // Transfers the unique ID of the given value to this value. We keep our // old ID as an alias. void TransferUniqueID(MutableVal* mv); // MutableVals can have properties (let's refrain from calling them // attributes!). Most properties are recursive. If a derived object // can contain MutableVals itself, the object has to override // {Add,Remove}Properties(). RecursiveProp(state) masks out all non- // recursive properties. If this is non-null, an overriden method must // call itself with RecursiveProp(state) as argument for all contained // values. (In any case, don't forget to call the parent's method.) typedef char Properties; static const int PERSISTENT = 0x01; static const int SYNCHRONIZED = 0x02; // Tracked by NotifierRegistry, not recursive. static const int TRACKED = 0x04; int RecursiveProps(int prop) const { return prop & ~TRACKED; } Properties GetProperties() const { return props; } virtual bool AddProperties(Properties state); virtual bool RemoveProperties(Properties state); // Whether StateAccess:LogAccess needs to be called. bool LoggingAccess() const { #ifndef DEBUG return props & (SYNCHRONIZED|PERSISTENT|TRACKED); #else return debug_logger.IsVerbose() || (props & (SYNCHRONIZED|PERSISTENT|TRACKED)); #endif } virtual uint64 LastModified() const { return last_modified; } // Mark value as changed. void Modified() { last_modified = IncreaseTimeCounter(); } protected: MutableVal(BroType* t) : Val(t) { props = 0; id = 0; last_modified = SerialObj::ALWAYS; } MutableVal() { props = 0; id = 0; last_modified = SerialObj::ALWAYS; } ~MutableVal(); friend class ID; friend class Val; void SetID(ID* arg_id) { Unref(id); id = arg_id; } DECLARE_SERIAL(MutableVal); private: ID* Bind() const; mutable ID* id; list aliases; Properties props; uint64 last_modified; }; #define Microseconds 1e-6 #define Milliseconds 1e-3 #define Seconds 1.0 #define Minutes (60*Seconds) #define Hours (60*Minutes) #define Days (24*Hours) class IntervalVal : public Val { public: IntervalVal(double quantity, double units); protected: IntervalVal() {} void ValDescribe(ODesc* d) const; DECLARE_SERIAL(IntervalVal); }; // We have four different port name spaces: TCP, UDP, ICMP, and UNKNOWN. // We distinguish between them based on the bits specified in the *_PORT_MASK // entries specified below. #define NUM_PORT_SPACES 4 #define PORT_SPACE_MASK 0x30000 #define TCP_PORT_MASK 0x10000 #define UDP_PORT_MASK 0x20000 #define ICMP_PORT_MASK 0x30000 class PortVal : public Val { public: // Constructors - both take the port number in host order. PortVal(uint32 p, TransportProto port_type); PortVal(uint32 p); // used for already-massaged port value. Val* SizeVal() const { return new Val(val.uint_val, TYPE_INT); } // Returns the port number in host order (not including the mask). uint32 Port() const; // Tests for protocol types. int IsTCP() const; int IsUDP() const; int IsICMP() const; TransportProto PortType() const { if ( IsTCP() ) return TRANSPORT_TCP; else if ( IsUDP() ) return TRANSPORT_UDP; else if ( IsICMP() ) return TRANSPORT_ICMP; else return TRANSPORT_UNKNOWN; } protected: friend class Val; PortVal() {} void ValDescribe(ODesc* d) const; DECLARE_SERIAL(PortVal); }; class AddrVal : public Val { public: AddrVal(const char* text); ~AddrVal(); Val* SizeVal() const; // Constructor for address already in network order. AddrVal(uint32 addr); // IPv4. AddrVal(const uint32 addr[4]); // IPv6. AddrVal(const IPAddr& addr); unsigned int MemoryAllocation() const; protected: friend class Val; AddrVal() {} AddrVal(TypeTag t) : Val(t) { } AddrVal(BroType* t) : Val(t) { } DECLARE_SERIAL(AddrVal); }; class SubNetVal : public Val { public: SubNetVal(const char* text); SubNetVal(const char* text, int width); SubNetVal(uint32 addr, int width); // IPv4. SubNetVal(const uint32 addr[4], int width); // IPv6. SubNetVal(const IPAddr& addr, int width); SubNetVal(const IPPrefix& prefix); ~SubNetVal(); Val* SizeVal() const; const IPAddr& Prefix() const; int Width() const; IPAddr Mask() const; bool Contains(const IPAddr& addr) const; unsigned int MemoryAllocation() const; protected: friend class Val; SubNetVal() {} void ValDescribe(ODesc* d) const; DECLARE_SERIAL(SubNetVal); }; class StringVal : public Val { public: StringVal(BroString* s); StringVal(const char* s); StringVal(const string& s); StringVal(int length, const char* s); Val* SizeVal() const { return new Val(val.string_val->Len(), TYPE_COUNT); } int Len() { return AsString()->Len(); } const u_char* Bytes() { return AsString()->Bytes(); } const char* CheckString() { return AsString()->CheckString(); } // Note that one needs to de-allocate the return value of // ExpandedString() to avoid a memory leak. // char* ExpandedString(int format = BroString::EXPANDED_STRING) // { return AsString()->ExpandedString(format); } StringVal* ToUpper(); unsigned int MemoryAllocation() const; protected: friend class Val; StringVal() {} void ValDescribe(ODesc* d) const; DECLARE_SERIAL(StringVal); }; class PatternVal : public Val { public: PatternVal(RE_Matcher* re); ~PatternVal(); int AddTo(Val* v, int is_first_init) const; void SetMatcher(RE_Matcher* re); unsigned int MemoryAllocation() const; protected: friend class Val; PatternVal() {} void ValDescribe(ODesc* d) const; DECLARE_SERIAL(PatternVal); }; // ListVals are mainly used to index tables that have more than one // element in their index. class ListVal : public Val { public: ListVal(TypeTag t); ~ListVal(); TypeTag BaseTag() const { return tag; } Val* SizeVal() const { return new Val(vals.length(), TYPE_COUNT); } int Length() const { return vals.length(); } Val* Index(const int n) { return vals[n]; } const Val* Index(const int n) const { return vals[n]; } // Returns an RE_Matcher() that will match any string that // includes embedded within it one of the patterns listed // (as a string, e.g., "foo|bar") in this ListVal. // // Assumes that all of the strings in the list are NUL-terminated // and do not have any embedded NULs. // // The return RE_Matcher has not yet been compiled. RE_Matcher* BuildRE() const; void Append(Val* v); // Returns a Set representation of the list (which must be homogeneous). TableVal* ConvertToSet() const; const val_list* Vals() const { return &vals; } val_list* Vals() { return &vals; } void Describe(ODesc* d) const; unsigned int MemoryAllocation() const; protected: friend class Val; ListVal() {} DECLARE_SERIAL(ListVal); val_list vals; TypeTag tag; }; extern double bro_start_network_time; class TableEntryVal { public: TableEntryVal(Val* v) { val = v; last_access_time = network_time; expire_access_time = last_read_update = int(network_time - bro_start_network_time); } ~TableEntryVal() { } Val* Value() { return val; } void Ref() { val->Ref(); } void Unref() { ::Unref(val); } // Returns/sets time of last expiration relevant access to this value. double ExpireAccessTime() const { return bro_start_network_time + expire_access_time; } void SetExpireAccess(double time) { expire_access_time = int(time - bro_start_network_time); } // Returns/sets time of when we propagated the last OP_READ_IDX // for this item. double LastReadUpdate() const { return bro_start_network_time + last_read_update; } void SetLastReadUpdate(double time) { last_read_update = int(time - bro_start_network_time); } protected: friend class TableVal; Val* val; double last_access_time; // The next two entries store seconds since Bro's start. We use // ints here to save a few bytes, as we do not need a high resolution // for these anyway. int expire_access_time; int last_read_update; }; class TableValTimer : public Timer { public: TableValTimer(TableVal* val, double t); ~TableValTimer(); virtual void Dispatch(double t, int is_expire); TableVal* Table() { return table; } protected: TableVal* table; }; class CompositeHash; class TableVal : public MutableVal { public: TableVal(TableType* t, Attributes* attrs = 0); ~TableVal(); // Returns true if the assignment typechecked, false if not. // Second version takes a HashKey and Unref()'s it when done. // If we're a set, new_val has to be nil. // If we aren't a set, index may be nil in the second version. int Assign(Val* index, Val* new_val, Opcode op = OP_ASSIGN); int Assign(Val* index, HashKey* k, Val* new_val, Opcode op = OP_ASSIGN); Val* SizeVal() const { return new Val(Size(), TYPE_COUNT); } // Add the entire contents of the table to the given value, // which must also be a TableVal. // Returns true if the addition typechecked, false if not. // If is_first_init is true, then this is the *first* initialization // (and so should be strictly adding new elements). int AddTo(Val* v, int is_first_init) const; // Same but allows suppression of state operations. int AddTo(Val* v, int is_first_init, bool propagate_ops) const; // Remove the entire contents. void RemoveAll(); // Remove the entire contents of the table from the given value. // which must also be a TableVal. // Returns true if the addition typechecked, false if not. int RemoveFrom(Val* v) const; // Expands any lists in the index into multiple initializations. // Returns true if the initializations typecheck, false if not. int ExpandAndInit(Val* index, Val* new_val); // Returns the element's value if it exists in the table, // nil otherwise. Note, "index" is not const because we // need to Ref/Unref it when calling the default function. Val* Lookup(Val* index, bool use_default_val = true); // Sets the timestamp for the given index to network time. // Returns false if index does not exist. bool UpdateTimestamp(Val* index); // Returns the index corresponding to the given HashKey. ListVal* RecoverIndex(const HashKey* k) const; // Returns the element if it was in the table, false otherwise. Val* Delete(const Val* index); Val* Delete(const HashKey* k); // Returns a ListVal representation of the table (which must be a set). ListVal* ConvertToList(TypeTag t=TYPE_ANY) const; ListVal* ConvertToPureList() const; // must be single index type void SetAttrs(Attributes* attrs); Attr* FindAttr(attr_tag t) const { return attrs ? attrs->FindAttr(t) : 0; } Attributes* Attrs() { return attrs; } // Returns the size of the table. int Size() const { return AsTable()->Length(); } int RecursiveSize() const; void Describe(ODesc* d) const; void InitTimer(double delay); void DoExpire(double t); unsigned int MemoryAllocation() const; void ClearTimer(Timer* t) { if ( timer == t ) timer = 0; } HashKey* ComputeHash(const Val* index) const { return table_hash->ComputeHash(index, 1); } protected: friend class Val; friend class StateAccess; TableVal() {} void Init(TableType* t); void CheckExpireAttr(attr_tag at); int ExpandCompoundAndInit(val_list* vl, int k, Val* new_val); int CheckAndAssign(Val* index, Val* new_val, Opcode op = OP_ASSIGN); bool AddProperties(Properties arg_state); bool RemoveProperties(Properties arg_state); // Calculates default value for index. Returns 0 if none. Val* Default(Val* index); // Calls &expire_func and returns its return interval; // takes ownership of the reference. double CallExpireFunc(Val *idx); // Propagates a read operation if necessary. void ReadOperation(Val* index, TableEntryVal *v); DECLARE_SERIAL(TableVal); TableType* table_type; CompositeHash* table_hash; Attributes* attrs; double expire_time; Expr* expire_expr; TableValTimer* timer; IterCookie* expire_cookie; PrefixTable* subnets; Val* def_val; }; class RecordVal : public MutableVal { public: RecordVal(RecordType* t); ~RecordVal(); Val* SizeVal() const { return new Val(record_type->NumFields(), TYPE_COUNT); } void Assign(int field, Val* new_val, Opcode op = OP_ASSIGN); Val* Lookup(int field) const; // Does not Ref() value. Val* LookupWithDefault(int field) const; // Does Ref() value. /** * Looks up the value of a field by field name. If the field doesn't * exist in the record type, it's an internal error: abort. * @param field name of field to lookup. * @param with_default whether to rely on field's &default attribute when * the field has yet to be initialized. * @return the value in field \a field. It is Ref()'d only if * \a with_default is true. */ Val* Lookup(const char* field, bool with_default = false) const; void Describe(ODesc* d) const; // This is an experiment to associate a BroObj within the // event engine to a record value in bro script. void SetOrigin(BroObj* o) { origin = o; } BroObj* GetOrigin() const { return origin; } // Returns a new value representing the value coerced to the given // type. If coercion is not possible, returns 0. The non-const // version may return the current value ref'ed if its type matches // directly. // // *aggr* is optional; if non-zero, we add to it. See // Expr::InitVal(). We leave it out in the non-const version to make // the choice unambigious. // // The *allow_orphaning* parameter allows for a record to be demoted // down to a record type that contains less fields. RecordVal* CoerceTo(const RecordType* other, Val* aggr, bool allow_orphaning = false) const; RecordVal* CoerceTo(RecordType* other, bool allow_orphaning = false); unsigned int MemoryAllocation() const; void DescribeReST(ODesc* d) const; protected: friend class Val; RecordVal() {} bool AddProperties(Properties arg_state); bool RemoveProperties(Properties arg_state); DECLARE_SERIAL(RecordVal); RecordType* record_type; BroObj* origin; }; class EnumVal : public Val { public: EnumVal(int i, EnumType* t) : Val(t) { val.int_val = i; type = t; } Val* SizeVal() const { return new Val(val.int_val, TYPE_INT); } protected: friend class Val; EnumVal() {} void ValDescribe(ODesc* d) const; DECLARE_SERIAL(EnumVal); }; class VectorVal : public MutableVal { public: VectorVal(VectorType* t); ~VectorVal(); Val* SizeVal() const { return new Val(uint32(val.vector_val->size()), TYPE_COUNT); } // Returns false if the type of the argument was wrong. // The vector will automatically grow to accomodate the index. // 'assigner" is the expression that is doing the assignment; // it's just used for pinpointing errors. // // Note: does NOT Ref() the element! Remember to do so unless // the element was just created and thus has refcount 1. // bool Assign(unsigned int index, Val* element, Opcode op = OP_ASSIGN); bool Assign(Val* index, Val* element, Opcode op = OP_ASSIGN) { return Assign(index->AsListVal()->Index(0)->CoerceToUnsigned(), element, op); } // Assigns the value to how_many locations starting at index. bool AssignRepeat(unsigned int index, unsigned int how_many, Val* element); // Returns nil if no element was at that value. // Lookup does NOT grow the vector to this size. // The Val* variant assumes that the index Val* has been type-checked. Val* Lookup(unsigned int index) const; Val* Lookup(Val* index) { bro_uint_t i = index->AsListVal()->Index(0)->CoerceToUnsigned(); return Lookup(static_cast(i)); } unsigned int Size() const { return val.vector_val->size(); } // Is there any way to reclaim previously-allocated memory when you // shrink a vector? The return value is the old size. unsigned int Resize(unsigned int new_num_elements); // Won't shrink size. unsigned int ResizeAtLeast(unsigned int new_num_elements); protected: friend class Val; VectorVal() { } bool AddProperties(Properties arg_state); bool RemoveProperties(Properties arg_state); void ValDescribe(ODesc* d) const; DECLARE_SERIAL(VectorVal); VectorType* vector_type; }; // Base class for values with types that are managed completely internally, // with no further script-level operators provided (other than bif // functions). See OpaqueVal.h for derived classes. class OpaqueVal : public Val { public: OpaqueVal(OpaqueType* t); virtual ~OpaqueVal(); protected: friend class Val; OpaqueVal() { } DECLARE_SERIAL(OpaqueVal); }; // Checks the given value for consistency with the given type. If an // exact match, returns it. If promotable, returns the promoted version, // Unref()'ing the original. If not a match, generates an error message // and returns nil, also Unref()'ing v. If is_init is true, then // the checking is done in the context of an initialization. extern Val* check_and_promote(Val* v, const BroType* t, int is_init); // Given a pointer to where a Val's core (i.e., its BRO value) resides, // returns a corresponding newly-created or Ref()'d Val. ptr must already // be properly aligned. Returns the size of the core in bytes in 'n'. // If t corresponds to a variable-length type, n must give the size on entry. Val* recover_val(void* ptr, BroType* t, int& n); extern int same_val(const Val* v1, const Val* v2); extern int same_atomic_val(const Val* v1, const Val* v2); extern bool is_atomic_val(const Val* v); extern void describe_vals(const val_list* vals, ODesc* d, int offset=0); extern void delete_vals(val_list* vals); // True if the given Val* has a vector type. inline bool is_vector(Val* v) { return v->Type()->Tag() == TYPE_VECTOR; } #endif