This repository has been archived by the owner on Sep 5, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Record Building Blocks
leandor edited this page Oct 21, 2016
·
2 revisions
The goal of this page is to describe the various classes used for describing record elements (subrecords). How they behave, and long-term goals in relation to these classes.
-
StringRecord
- Handles a subrecord that contains a null-terminated string -
NonNullStringRecord
- Handles a subrecord that contains a non-null-terminated string -
UnorderedPackedStrings
- Handles a subrecord with multiple null-terminated strings -
RawRecord
- Handles a subrecord with unknown data. Data is read in as raw bytes -
SimpleSubRecord<type, default=0>
- Use with simple data types that initialize to zero (int, etc). Use this version when it's unknown if the subrecord is required or optional. -
SimpleFloatSubRecord<default=0.0>
- Specialization ofSimpleSubRecord
for floats -
ReqSimpleSubRecord<type, default=0>
- Specialization ofSimpleSubRecord
that will always write the subrecord no matter the value. -
ReqSimpleFloatSubRecord<default=0.0>
- Specialization ofReqSimpleSubRecord
for floats. -
OptSimpleSubRecord<type, default=0>
- Specialization ofSimpleSubRecord
, that will only write the subrecord if it is not the default value. -
OptZeroSubRecord<type>
- likeOptSimpleSubRecord
, comments say it will still be considered Unloaded if they are equal to their default. Not entirely sure how these are different then the previous types though... -
OptSimpleFloatSubRecord<default=0.0>
- Specialization ofSimpleFloatSubRecord
that will only write the subrecord if it is not the default value. -
SemiOptSimpleSubRecord<type, default=0>
- almost eactly likeSimpleSubRecord
, except that once it has been loaded, it will always write out its applicable subrecord (as opposed toSimpleSubRecord
, which will no write it after being loaded if it is equal to the default). -
SemiOptSimpleFloatSubRecord<default=0.0
- specialization ofSemiOptSimpleSubRecord
for floats. -
SubRecord<type>
- likeSimpleSubRecord
, but for non-basic types. Use this kind of element when dealing withstructs
that directly map to the memory layout on disk. -
ReqSubRecord<type>
- specialization ofSubRecord
that will always write the subrecord -
OptSubRecord<type>
- specialization ofSubRecord
, where the subrecord will only be written if it is not equal to the default value, where the default is determined by the default constructor fortype
. -
SemiOptSubRecord<type>
- specialization ofSubRecord
, where the subrecord is only written if it was read in. -
OrderedPackedArray<type, cmp=std::less>
- Single subrecord with repeating elements oftype
, sorted. Iftype
does not have a less-than operator defined, then you must supply a custom function to do the comparisons. -
UnorderedPackedArray<type>
- Single subrecord with repeating elements oftype
. -
OrderedSparseArray<type, cmp=std::less>
- Multiple subrecords of the same type, each containing a single element oftype
, sorted. -
UnorderedSparseArray
- Multiple subrecords of the same type, each containing a single element oftype
. -
ReqCounted<type, countType, countRecord>
- Used to wrap around one of the***Array
classes. Used when one of the***Array
type subrecords is supposed to be preceeded by another subrecord that holds the count of items.countType
is the type of int to hold this (to correlate with the required size of the subrecord: ie UINT8 is the subrecord is supposed to be 1 byte, etc).countRecord
is the REV32 of the counting record. Lika otherReq***
subrecords, this one will always be written (the preceeding counting subrecord). An example from Skyrim: a record has keywords attached via multiple KWDA subrecord. The KWDAs are preceeded by a, 1-byte KSIZ subrecord denoting how many KWDA subrecords there are, define it like:ReqCounted<UnorderedSparseArray<FORMID>, UINT8, REV32(KSIZ)>
. -
OptCounted<type, countType, countRecord>
- LikeReqCounted
, but the counting subrecord will only be written if there are elements in the array.
-
OBMEEFIXSubRecord
- hacky support for OBME EFIX subrecord. Like an OptSubRecord, except if value->efixOverride == 0, then it gets unloaded
-
LStringRecord
- Handles translatable strings in Skyrim. If the TES4 record has the flag set for translation strings, then this subrecord is read in as an Id, then the string is looked up from the applicable strings files. Otherwise, it is treated the same as aStringRecord
. -
VMADRecord
- Reads in the data from VMAD subrecords.
DefaultSingleton<type>
- This is a singleton creator to create default values for ***SubRecord
type elements (ie: when it's defined using a struct
). Used internally by many of the above types, however it is useful to use this as well in the record API for deleting elements.
Standardize the interface to each of these classes:
- As it is currently, to get at the actual data contained in the record, for some types you use
->
, and for others you use.
. I'll probably standardize this to->
-
StringRecord
/LStringRecord
- overload==
to doequals
, so the only time you need to call a function for comparison is if you're doing case-insensitive comparison. - More overloaded assignment operators. As an example, currently for a
SimpleSubRecord<int>
, so assign the value you would have to dosubrecord.value = newValue;
. I want to provide a second overloaded=
to allow direct assignment without having to access.value
. - Indexing operator overloading for
***Array
types. Currently it's clunky in that you have to dosubrecord.value[index]
- Expose commonly used
std::vector
functions in the***Array
types. Similar to the above, it's currently clunky to call things likesubrecord.value.size()
, etc. - Come up with a good way to return the address of value, etc. This is mostly for the GetAttribute API function. Most cases you end up with code like:
&DNAM.value
andFULL.value
. Basically I want to take away the need to use.value
at all in the code. This one is tricky in that I don't want to overload the&
reference operator, as that can end up giving very unintuitive results in places. Perhaps do it in the form of a functions (addr()
), or overload the()
operator, or perhaps the*
operator. - I also want to combine the
***SimpleSubRecord
and***SimpleFloatRecord
types, via template specialization. Less names to remember that way. - Possibly do away with the
Req****
andOpt****
types, and instead implement wrapper templates (similar to theReqCounted
andOptCounted
templates) that will wrap around the applicable type. Once again, less names to remember that way.
Some of the content was adapted from Lojack's Wiki