Coding style cleanup, no functional change.

This commit is contained in:
Axel Dörfler 2017-01-19 20:48:07 +01:00
parent 991d9dbf6d
commit e5022f23b3
1 changed files with 296 additions and 290 deletions

View File

@ -74,31 +74,32 @@ union value {
*/
class Term {
public:
Term(int8 op) : fOp(op), fParent(NULL) {}
virtual ~Term() {}
Term(int8 op) : fOp(op), fParent(NULL) {}
virtual ~Term() {}
int8 Op() const { return fOp; }
int8 Op() const { return fOp; }
void SetParent(Term* parent) { fParent = parent; }
Term* Parent() const { return fParent; }
void SetParent(Term* parent) { fParent = parent; }
Term* Parent() const { return fParent; }
virtual status_t Match(Inode* inode, const char* attribute = NULL,
int32 type = 0, const uint8* key = NULL,
size_t size = 0) = 0;
virtual void Complement() = 0;
virtual status_t Match(Inode* inode,
const char* attribute = NULL,
int32 type = 0, const uint8* key = NULL,
size_t size = 0) = 0;
virtual void Complement() = 0;
virtual void CalculateScore(Index& index) = 0;
virtual int32 Score() const = 0;
virtual void CalculateScore(Index& index) = 0;
virtual int32 Score() const = 0;
virtual status_t InitCheck() = 0;
virtual status_t InitCheck() = 0;
#ifdef DEBUG
virtual void PrintToStream() = 0;
virtual void PrintToStream() = 0;
#endif
protected:
int8 fOp;
Term* fParent;
int8 fOp;
Term* fParent;
};
@ -115,51 +116,54 @@ protected:
*/
class Equation : public Term {
public:
Equation(char** expression);
virtual ~Equation();
Equation(char** _expression);
virtual ~Equation();
virtual status_t InitCheck();
virtual status_t InitCheck();
status_t ParseQuotedString(char** _start, char** _end);
char* CopyString(char* start, char* end);
virtual status_t Match(Inode* inode,
const char* attribute = NULL,
int32 type = 0, const uint8* key = NULL,
size_t size = 0);
virtual void Complement();
virtual status_t Match(Inode* inode, const char* attribute = NULL,
int32 type = 0, const uint8* key = NULL,
size_t size = 0);
virtual void Complement();
status_t PrepareQuery(Volume* volume, Index& index,
TreeIterator** iterator,
bool queryNonIndexed);
status_t GetNextMatching(Volume* volume,
TreeIterator* iterator,
struct dirent* dirent, size_t bufferSize);
status_t PrepareQuery(Volume* volume, Index& index,
TreeIterator** iterator, bool queryNonIndexed);
status_t GetNextMatching(Volume* volume, TreeIterator* iterator,
struct dirent* dirent, size_t bufferSize);
virtual void CalculateScore(Index &index);
virtual int32 Score() const { return fScore; }
virtual void CalculateScore(Index &index);
virtual int32 Score() const { return fScore; }
#ifdef DEBUG
virtual void PrintToStream();
virtual void PrintToStream();
#endif
private:
Equation(const Equation& other);
Equation& operator=(const Equation& other);
// no implementation
Equation(const Equation& other);
Equation& operator=(const Equation& other);
// no implementation
status_t ConvertValue(type_code type);
bool CompareTo(const uint8* value, uint16 size);
uint8* Value() const { return (uint8*)&fValue; }
status_t MatchEmptyString();
status_t _ParseQuotedString(char** _start, char** _end);
char* _CopyString(char* start, char* end);
status_t _ConvertValue(type_code type);
bool _CompareTo(const uint8* value, uint16 size);
uint8* _Value() const { return (uint8*)&fValue; }
status_t _MatchEmptyString();
char* fAttribute;
char* fString;
union value fValue;
type_code fType;
size_t fSize;
bool fIsPattern;
bool fIsSpecialTime;
private:
char* fAttribute;
char* fString;
union value fValue;
type_code fType;
size_t fSize;
bool fIsPattern;
bool fIsSpecialTime;
int32 fScore;
bool fHasIndex;
int32 fScore;
bool fHasIndex;
};
@ -168,40 +172,42 @@ private:
*/
class Operator : public Term {
public:
Operator(Term* left, int8 op, Term* right);
virtual ~Operator();
Operator(Term* left, int8 op, Term* right);
virtual ~Operator();
Term* Left() const { return fLeft; }
Term* Right() const { return fRight; }
Term* Left() const { return fLeft; }
Term* Right() const { return fRight; }
virtual status_t Match(Inode* inode, const char* attribute = NULL,
int32 type = 0, const uint8* key = NULL,
size_t size = 0);
virtual void Complement();
virtual status_t Match(Inode* inode,
const char* attribute = NULL,
int32 type = 0, const uint8* key = NULL,
size_t size = 0);
virtual void Complement();
virtual void CalculateScore(Index& index);
virtual int32 Score() const;
virtual void CalculateScore(Index& index);
virtual int32 Score() const;
virtual status_t InitCheck();
virtual status_t InitCheck();
#ifdef DEBUG
virtual void PrintToStream();
virtual void PrintToStream();
#endif
private:
Operator(const Operator& other);
Operator& operator=(const Operator& other);
// no implementation
Operator(const Operator& other);
Operator& operator=(const Operator& other);
// no implementation
Term* fLeft;
Term* fRight;
private:
Term* fLeft;
Term* fRight;
};
// #pragma mark -
Equation::Equation(char** expr)
Equation::Equation(char** _expression)
:
Term(OP_EQUATION),
fAttribute(NULL),
@ -209,7 +215,7 @@ Equation::Equation(char** expr)
fType(0),
fIsPattern(false)
{
char* string = *expr;
char* string = *_expression;
char* start = string;
char* end = NULL;
@ -220,7 +226,7 @@ Equation::Equation(char** expr)
if (*start == '"' || *start == '\'') {
// string is quoted (start has to be on the beginning of a string)
if (ParseQuotedString(&start, &end) < B_OK)
if (_ParseQuotedString(&start, &end) < B_OK)
return;
// set string to a valid start of the equation symbol
@ -228,7 +234,7 @@ Equation::Equation(char** expr)
skipWhitespace(&string);
if (*string != '=' && *string != '<' && *string != '>'
&& *string != '!') {
*expr = string;
*_expression = string;
return;
}
} else {
@ -274,7 +280,7 @@ Equation::Equation(char** expr)
// any invalid characters will be rejected
default:
*expr = string;
*_expression = string;
return;
}
@ -286,14 +292,14 @@ Equation::Equation(char** expr)
// allocate & copy the attribute string
fAttribute = CopyString(start, end);
fAttribute = _CopyString(start, end);
if (fAttribute == NULL)
return;
start = string;
if (*start == '"' || *start == '\'') {
// string is quoted (start has to be on the beginning of a string)
if (ParseQuotedString(&start, &end) < B_OK)
if (_ParseQuotedString(&start, &end) < B_OK)
return;
string = end + 2;
@ -306,19 +312,19 @@ Equation::Equation(char** expr)
skipWhitespaceReverse(&end, start);
}
// at this point, "start" will point to the first character of the value,
// At this point, "start" will point to the first character of the value,
// "end" will point to its last character, and "start" to the first non-
// whitespace character after the value string
// whitespace character after the value string.
fString = CopyString(start, end);
fString = _CopyString(start, end);
if (fString == NULL)
return;
// patterns are only allowed for these operations (and strings)
// Patterns are only allowed for these operations (and strings)
if (fOp == OP_EQUAL || fOp == OP_UNEQUAL) {
fIsPattern = isPattern(fString);
if (fIsPattern && isValidPattern(fString) < B_OK) {
// we only want to have valid patterns; setting fString
// Only valid patterns are allowed; setting fString
// to NULL will cause InitCheck() to fail
free(fString);
fString = NULL;
@ -333,7 +339,7 @@ Equation::Equation(char** expr)
// too one day.
fIsSpecialTime = !strcmp(fAttribute, "last_modified");
*expr = string;
*_expression = string;
}
@ -354,184 +360,6 @@ Equation::InitCheck()
}
status_t
Equation::ParseQuotedString(char** _start, char** _end)
{
char* start = *_start;
char quote = *start++;
char* end = start;
for (; *end && *end != quote; end++) {
if (*end == '\\')
end++;
}
if (*end == '\0')
return B_BAD_VALUE;
*_start = start;
*_end = end - 1;
return B_OK;
}
char*
Equation::CopyString(char* start, char* end)
{
// end points to the last character of the string - and the length
// also has to include the null-termination
int32 length = end + 2 - start;
// just to make sure; since that's the max. attribute name length and
// the max. string in an index, it make sense to have it that way
if (length > INODE_FILE_NAME_LENGTH || length <= 0)
return NULL;
char* copy = (char*)malloc(length);
if (copy == NULL)
return NULL;
memcpy(copy, start, length - 1);
copy[length - 1] = '\0';
return copy;
}
status_t
Equation::ConvertValue(type_code type)
{
// Has the type already been converted?
if (type == fType)
return B_OK;
char* string = fString;
switch (type) {
case B_MIME_STRING_TYPE:
type = B_STRING_TYPE;
// supposed to fall through
case B_STRING_TYPE:
strncpy(fValue.String, string, INODE_FILE_NAME_LENGTH);
fValue.String[INODE_FILE_NAME_LENGTH - 1] = '\0';
fSize = strlen(fValue.String);
break;
case B_INT32_TYPE:
fValue.Int32 = strtol(string, &string, 0);
fSize = sizeof(int32);
break;
case B_UINT32_TYPE:
fValue.Int32 = strtoul(string, &string, 0);
fSize = sizeof(uint32);
break;
case B_INT64_TYPE:
fValue.Int64 = strtoll(string, &string, 0);
fSize = sizeof(int64);
break;
case B_UINT64_TYPE:
fValue.Uint64 = strtoull(string, &string, 0);
fSize = sizeof(uint64);
break;
case B_FLOAT_TYPE:
fValue.Float = strtod(string, &string);
fSize = sizeof(float);
break;
case B_DOUBLE_TYPE:
fValue.Double = strtod(string, &string);
fSize = sizeof(double);
break;
default:
FATAL(("query value conversion to 0x%x requested!\n", (int)type));
// should we fail here or just do a safety int32 conversion?
return B_ERROR;
}
fType = type;
// patterns are only allowed for string types
if (fType != B_STRING_TYPE && fIsPattern)
fIsPattern = false;
return B_OK;
}
/*! Returns true when the key matches the equation. You have to
call ConvertValue() before this one.
*/
bool
Equation::CompareTo(const uint8* value, uint16 size)
{
int32 compare;
// fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or
// OP_UNEQUAL
if (fIsPattern) {
// we have already validated the pattern, so we don't check for failing
// here - if something is broken, and matchString() returns an error,
// we just don't match
compare = matchString(fValue.String, (char*)value) == MATCH_OK ? 0 : 1;
} else if (fIsSpecialTime) {
// the index is a shifted int64 index, but we have to match
// against an unshifted value (i.e. the last_modified index)
int64 timeValue = *(int64*)value >> INODE_TIME_SHIFT;
compare = compareKeys(fType, &timeValue, sizeof(int64), &fValue.Int64,
sizeof(int64));
} else
compare = compareKeys(fType, value, size, Value(), fSize);
switch (fOp) {
case OP_EQUAL:
return compare == 0;
case OP_UNEQUAL:
return compare != 0;
case OP_LESS_THAN:
return compare < 0;
case OP_LESS_THAN_OR_EQUAL:
return compare <= 0;
case OP_GREATER_THAN:
return compare > 0;
case OP_GREATER_THAN_OR_EQUAL:
return compare >= 0;
}
FATAL(("Unknown/Unsupported operation: %d\n", fOp));
return false;
}
void
Equation::Complement()
{
D(if (fOp <= OP_EQUATION || fOp > OP_LESS_THAN_OR_EQUAL) {
FATAL(("op out of range!"));
return;
});
int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL,
OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN};
fOp = complementOp[fOp - OP_EQUAL];
}
status_t
Equation::MatchEmptyString()
{
// There is no matching attribute, we will just bail out if we
// already know that our value is not of a string type.
// If not, it will be converted to a string - and then be compared with "".
// That's why we have to call ConvertValue() here - but it will be
// a cheap call for the next time
// TODO: Should we do this only for OP_UNEQUAL?
if (fType != 0 && fType != B_STRING_TYPE)
return NO_MATCH;
status_t status = ConvertValue(B_STRING_TYPE);
if (status == B_OK)
status = CompareTo((const uint8*)"", fSize) ? MATCH_OK : NO_MATCH;
return status;
}
/*! Matches the inode's attribute value with the equation.
Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went
wrong.
@ -550,7 +378,7 @@ Equation::Match(Inode* inode, const char* attributeName, int32 type,
if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
if (key == NULL) {
if (type == B_STRING_TYPE)
return MatchEmptyString();
return _MatchEmptyString();
return NO_MATCH;
}
@ -623,13 +451,13 @@ Equation::Match(Inode* inode, const char* attributeName, int32 type,
}
inode->ReleaseAttribute(attribute);
} else
return MatchEmptyString();
return _MatchEmptyString();
}
}
// prepare own value for use, if it is possible to convert it
status_t status = ConvertValue(type);
status_t status = _ConvertValue(type);
if (status == B_OK)
status = CompareTo(buffer, size) ? MATCH_OK : NO_MATCH;
status = _CompareTo(buffer, size) ? MATCH_OK : NO_MATCH;
if (locked)
recursive_lock_unlock(&inode->SmallDataLock());
@ -639,36 +467,16 @@ Equation::Match(Inode* inode, const char* attributeName, int32 type,
void
Equation::CalculateScore(Index &index)
Equation::Complement()
{
// As always, these values could be tuned and refined.
// And the code could also need some real world testing :-)
// do we have to operate on a "foreign" index?
if (fOp == OP_UNEQUAL || index.SetTo(fAttribute) < B_OK) {
fScore = 0;
D(if (fOp <= OP_EQUATION || fOp > OP_LESS_THAN_OR_EQUAL) {
FATAL(("op out of range!"));
return;
}
});
// if we have a pattern, how much does it help our search?
if (fIsPattern)
fScore = getFirstPatternSymbol(fString) << 3;
else {
// Score by operator
if (fOp == OP_EQUAL)
// higher than pattern="255 chars+*"
fScore = 2048;
else
// the pattern search is regarded cheaper when you have at
// least one character to set your index to
fScore = 5;
}
// take index size into account (1024 is the current node size
// in our B+trees)
// 2048 * 2048 == 4194304 is the maximum score (for an empty
// tree, since the header + 1 node are already 2048 bytes)
fScore = fScore * ((2048 * 1024LL) / index.Node()->Size());
int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL,
OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN};
fOp = complementOp[fOp - OP_EQUAL];
}
@ -701,7 +509,7 @@ Equation::PrepareQuery(Volume* /*volume*/, Index& index,
type = index.Type();
}
if (ConvertValue(type) < B_OK)
if (_ConvertValue(type) < B_OK)
return B_BAD_VALUE;
BPlusTree* tree = index.Node()->Tree();
@ -753,7 +561,7 @@ Equation::PrepareQuery(Volume* /*volume*/, Index& index,
if (status == B_ENTRY_NOT_FOUND)
return B_OK;
} else {
status = (*iterator)->Find(Value(), keySize);
status = (*iterator)->Find(_Value(), keySize);
if (fOp == OP_EQUAL && !fIsPattern)
return status;
else if (status == B_ENTRY_NOT_FOUND
@ -787,7 +595,7 @@ Equation::GetNextMatching(Volume* volume, TreeIterator* iterator,
// only compare against the index entry when this is the correct
// index for the equation
if (fHasIndex && duplicate < 2
&& !CompareTo((uint8*)&indexValue, keyLength)) {
&& !_CompareTo((uint8*)&indexValue, keyLength)) {
// They aren't equal? Let the operation decide what to do. Since
// we always start at the beginning of the index (or the correct
// position), only some needs to be stopped if the entry doesn't
@ -876,6 +684,204 @@ Equation::GetNextMatching(Volume* volume, TreeIterator* iterator,
}
void
Equation::CalculateScore(Index &index)
{
// As always, these values could be tuned and refined.
// And the code could also need some real world testing :-)
// do we have to operate on a "foreign" index?
if (fOp == OP_UNEQUAL || index.SetTo(fAttribute) < B_OK) {
fScore = 0;
return;
}
// if we have a pattern, how much does it help our search?
if (fIsPattern)
fScore = getFirstPatternSymbol(fString) << 3;
else {
// Score by operator
if (fOp == OP_EQUAL)
// higher than pattern="255 chars+*"
fScore = 2048;
else
// the pattern search is regarded cheaper when you have at
// least one character to set your index to
fScore = 5;
}
// take index size into account (1024 is the current node size
// in our B+trees)
// 2048 * 2048 == 4194304 is the maximum score (for an empty
// tree, since the header + 1 node are already 2048 bytes)
fScore = fScore * ((2048 * 1024LL) / index.Node()->Size());
}
status_t
Equation::_ParseQuotedString(char** _start, char** _end)
{
char* start = *_start;
char quote = *start++;
char* end = start;
for (; *end && *end != quote; end++) {
if (*end == '\\')
end++;
}
if (*end == '\0')
return B_BAD_VALUE;
*_start = start;
*_end = end - 1;
return B_OK;
}
char*
Equation::_CopyString(char* start, char* end)
{
// end points to the last character of the string - and the length
// also has to include the null-termination
int32 length = end + 2 - start;
// just to make sure; since that's the max. attribute name length and
// the max. string in an index, it make sense to have it that way
if (length > INODE_FILE_NAME_LENGTH || length <= 0)
return NULL;
char* copy = (char*)malloc(length);
if (copy == NULL)
return NULL;
memcpy(copy, start, length - 1);
copy[length - 1] = '\0';
return copy;
}
status_t
Equation::_ConvertValue(type_code type)
{
// Has the type already been converted?
if (type == fType)
return B_OK;
char* string = fString;
switch (type) {
case B_MIME_STRING_TYPE:
type = B_STRING_TYPE;
// supposed to fall through
case B_STRING_TYPE:
strncpy(fValue.String, string, INODE_FILE_NAME_LENGTH);
fValue.String[INODE_FILE_NAME_LENGTH - 1] = '\0';
fSize = strlen(fValue.String);
break;
case B_INT32_TYPE:
fValue.Int32 = strtol(string, &string, 0);
fSize = sizeof(int32);
break;
case B_UINT32_TYPE:
fValue.Int32 = strtoul(string, &string, 0);
fSize = sizeof(uint32);
break;
case B_INT64_TYPE:
fValue.Int64 = strtoll(string, &string, 0);
fSize = sizeof(int64);
break;
case B_UINT64_TYPE:
fValue.Uint64 = strtoull(string, &string, 0);
fSize = sizeof(uint64);
break;
case B_FLOAT_TYPE:
fValue.Float = strtod(string, &string);
fSize = sizeof(float);
break;
case B_DOUBLE_TYPE:
fValue.Double = strtod(string, &string);
fSize = sizeof(double);
break;
default:
FATAL(("query value conversion to 0x%x requested!\n", (int)type));
// should we fail here or just do a safety int32 conversion?
return B_ERROR;
}
fType = type;
// patterns are only allowed for string types
if (fType != B_STRING_TYPE && fIsPattern)
fIsPattern = false;
return B_OK;
}
/*! Returns true when the key matches the equation. You have to
call ConvertValue() before this one.
*/
bool
Equation::_CompareTo(const uint8* value, uint16 size)
{
int32 compare;
// fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or
// OP_UNEQUAL
if (fIsPattern) {
// we have already validated the pattern, so we don't check for failing
// here - if something is broken, and matchString() returns an error,
// we just don't match
compare = matchString(fValue.String, (char*)value) == MATCH_OK ? 0 : 1;
} else if (fIsSpecialTime) {
// the index is a shifted int64 index, but we have to match
// against an unshifted value (i.e. the last_modified index)
int64 timeValue = *(int64*)value >> INODE_TIME_SHIFT;
compare = compareKeys(fType, &timeValue, sizeof(int64), &fValue.Int64,
sizeof(int64));
} else
compare = compareKeys(fType, value, size, _Value(), fSize);
switch (fOp) {
case OP_EQUAL:
return compare == 0;
case OP_UNEQUAL:
return compare != 0;
case OP_LESS_THAN:
return compare < 0;
case OP_LESS_THAN_OR_EQUAL:
return compare <= 0;
case OP_GREATER_THAN:
return compare > 0;
case OP_GREATER_THAN_OR_EQUAL:
return compare >= 0;
}
FATAL(("Unknown/Unsupported operation: %d\n", fOp));
return false;
}
status_t
Equation::_MatchEmptyString()
{
// There is no matching attribute, we will just bail out if we
// already know that our value is not of a string type.
// If not, it will be converted to a string - and then be compared with "".
// That's why we have to call ConvertValue() here - but it will be
// a cheap call for the next time
// TODO: Should we do this only for OP_UNEQUAL?
if (fType != 0 && fType != B_STRING_TYPE)
return NO_MATCH;
status_t status = _ConvertValue(B_STRING_TYPE);
if (status == B_OK)
status = _CompareTo((const uint8*)"", fSize) ? MATCH_OK : NO_MATCH;
return status;
}
// #pragma mark -