3 Copyright (C) 2006 Damien Katz
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #ifndef FABRIC_ELEMENT_H
22 #define FABRIC_ELEMENT_H
26 #include "FabricSTL.h"
30 #define snprintf _snprintf
33 #pragma pack(push, r1, 4)
38 // The order of the elements in the Enum determines their collation sequence.
59 virtual const TextElement
ToText(MA
* ma
) const = 0;
60 virtual bool ToBool() const = 0;
61 virtual ElementType
GetType() const = 0;
63 virtual const NumberElement
ToNumber() const;
64 virtual const ErrorElement
ToError() const;
65 virtual const KeywordElement
ToKeyword() const;
67 virtual long ToLong() const;
70 const Element
ConvertTo(MA
* ma
, ElementType
) const;
74 class TextElement
: public ElementBase
76 const unsigned char* m_p
;
79 static unsigned char DefaultNullChar
;
84 : m_p(&DefaultNullChar
), m_len(0)
87 TextElement(const char* pStr
, size_t len
)
88 : m_p((const unsigned char*)pStr
), m_len(len
)
91 TextElement(const char* pStr
)
92 : m_p((const unsigned char*)pStr
), m_len(strlen(pStr
))
95 virtual bool ToBool() const
97 // non null strings are true
101 virtual ElementType
GetType() const
106 const char* Ptr() const
108 return (const char*)m_p
;
111 size_t Length() const
116 const TextElement
ToText(MA
* ma
) const
121 TextElement
Concat(MA
* ma
, const TextElement
& other
)
123 char* pNewBuffer
= new(ma
) char[m_len
+ other
.m_len
];
125 // copy in our string
126 memcpy(pNewBuffer
, m_p
, m_len
);
128 // copy in the other string
129 memcpy(pNewBuffer
+ m_len
, other
.m_p
, other
.m_len
);
131 return TextElement(pNewBuffer
, m_len
+ other
.m_len
);
134 virtual const NumberElement
ToNumber() const;
136 int Compare(const TextElement
& right
) const
138 return Compare(*this, right
);
141 int CompareI(const TextElement
& right
) const
143 return CompareI(*this, right
);
146 int Equals(const TextElement
& right
) const
148 return Compare(*this, right
) == 0;
151 int EqualsI(const TextElement
& right
) const
153 return CompareI(*this, right
) == 0;
156 static int Compare(const TextElement
& left
, const TextElement
& right
);
157 static int CompareI(const TextElement
& left
, const TextElement
& right
);
159 int Characters() const;
161 bool operator < (const TextElement
& right
) const
163 return Compare(*this, right
) == 1;
166 char* ToNullTermStr(MA
* ma
) const
168 char* pReturnValue
= new(ma
) char[m_len
+ 1];
169 memcpy(pReturnValue
, m_p
, m_len
);
170 pReturnValue
[m_len
] = 0;
175 TextElement
ExtractTrailingNumber(long* pTrailingNumber
) const;
177 static TextElement
MakeCopy(MA
* ma
, const char* pString
)
179 return MakeCopy(ma
, pString
, strlen(pString
));
182 static TextElement
MakeCopy(MA
* ma
, const char* pString
, size_t len
)
184 char* p
= new(ma
) char[len
];
185 memcpy(p
, pString
, len
);
187 return TextElement(p
, len
);
190 static TextElement
MakeCopy(MA
* ma
, const TextElement
& text
)
192 char* p
= new(ma
) char[text
.m_len
];
193 memcpy(p
, text
.m_p
, text
.m_len
);
195 return TextElement(p
, text
.m_len
);
203 bool Begins(const TextElement
& t
) const
205 if (t
.m_len
> m_len
) {
208 if (memcmp(t
.m_p
, m_p
, t
.m_len
) == 0) {
217 #define TEXT_ELEMENT(stringLiteral) TextElement(stringLiteral, sizeof(stringLiteral)-1)
219 class NumberElement
: public ElementBase
223 NumberElement(double number
)
228 operator double() const
233 virtual bool ToBool() const
238 virtual ElementType
GetType() const
243 const TextElement
ToText(MA
* ma
) const
246 snprintf(buffer
, sizeof(buffer
)-1, "%.f", m_value
);
248 return TextElement::MakeCopy(ma
, buffer
);
251 const NumberElement
ToNumber() const
268 StringBuilder(MA
* maIn
, size_t initialSize
)
271 m_pBegin
= m_pCurrent
= new(ma
) char[initialSize
];
273 m_size
= initialSize
;
276 void Append(const char* str
, size_t appendLen
)
278 size_t currentLen
= m_pCurrent
- m_pBegin
;
279 size_t spaceLeft
= m_size
- currentLen
;
280 if (appendLen
+ 1 <= spaceLeft
) {
281 memcpy(m_pCurrent
, str
, appendLen
);
282 m_pCurrent
+= appendLen
;
286 size_t newSize
= (currentLen
+ appendLen
)*2;
287 char* pNew
= new(ma
) char[newSize
];
288 memcpy(pNew
, m_pBegin
, currentLen
);
289 memcpy(pNew
+ currentLen
, str
, appendLen
);
292 m_pCurrent
= pNew
+ currentLen
+ appendLen
;
297 StringBuilder
& operator += (const char* str
)
299 Append(str
,strlen(str
));
303 StringBuilder
& operator += (const TextElement
& t
)
305 Append(t
.Ptr(), t
.Length());
309 StringBuilder
& operator += (int ival
)
312 snprintf(buffer
, sizeof(buffer
)-1, "%i", ival
);
313 Append(buffer
, strlen(buffer
));
317 // always null terminated
318 operator const char* ()
323 size_t Length() const
325 return m_pCurrent
- m_pBegin
;
330 class TimeElement
: public ElementBase
337 class ErrorElement
: public ElementBase
339 const char* m_typeId
;
340 const char* m_message
;
342 ErrorElement(RuntimeException
& e
)
343 : m_typeId(e
.typeId()), m_message(e
.what())
346 ErrorElement(const char* typeId
, const char* message
)
347 : m_typeId(typeId
), m_message(message
)
350 virtual bool ToBool() const
355 virtual ElementType
GetType() const
357 return RUNTIME_ERROR
;
360 virtual const TextElement
ToText(MA
* ma
) const
362 StringBuilder
str(ma
,100);
366 return TextElement(str
, str
.Length());
369 const TextElement
TypeId() const
371 return TextElement(m_typeId
);
374 const ErrorElement
ToError() const
382 class KeywordElement
: public ElementBase
384 // store the keyword text as a null terminated string
385 // with its atom. Using the atom makes keyword comparisons
386 // fast and using a null terminated string saves Element
387 // space by not having a length member.
388 const char* m_pKeyword
;
393 KeywordElement(IdAtom keywordID
, const char* pKeyword
)
394 : m_keywordID(keywordID
), m_pKeyword(pKeyword
)
403 ElementType
GetType() const
408 const TextElement
ToText(MA
* ma
) const
410 return TextElement(m_pKeyword
, strlen(m_pKeyword
));
413 const KeywordElement
ToKeyword() const
424 #define MAXSIZE(A,B) (A > B ? A : B)
426 #define ELEMENT_UNION_SIZE MAXSIZE(MAXSIZE(MAXSIZE(\
427 sizeof(NumberElement), \
428 sizeof(TextElement)), \
429 sizeof(ErrorElement)), \
430 sizeof(KeywordElement))
434 unsigned char m_element
[ELEMENT_UNION_SIZE
];
438 static const Element DefaultElement
;
440 Element(const Element
& elementIn
)
442 memcpy(m_element
, elementIn
.m_element
, sizeof(m_element
));
445 Element(const TextElement
& text
)
447 memcpy(m_element
, &text
, sizeof(text
));
450 Element(const char* pValue
, size_t len
)
452 TextElement
* p
= new((void*)m_element
) TextElement(pValue
, len
);
455 Element(const NumberElement
& number
)
457 memcpy(m_element
, &number
, sizeof(number
));
460 Element(const ErrorElement
& element
)
462 memcpy(m_element
, &element
, sizeof(element
));
465 Element(const KeywordElement
& element
)
467 memcpy(m_element
, &element
, sizeof(element
));
470 operator const ElementBase
*() const
472 return (const ElementBase
*)m_element
;
475 const ElementBase
* operator->() const
477 return (const ElementBase
*)m_element
;
480 ElementBase
* operator->()
482 return (ElementBase
*)m_element
;
485 Element(RuntimeException
& e
)
487 ErrorElement
* p
= new((void*)m_element
) ErrorElement(e
);
490 Element(KeywordElement
& keyword
)
492 memcpy(m_element
, &keyword
, sizeof(keyword
));
498 //This is guard to make sure we don't accidently expand the size of
499 // an element. 12 bytes, The first DWORD is vtable Id for the class,
500 // and each element then has 8 bytes to work with.
501 int size
= sizeof(Element
);
503 TextElement
* p
= new((void*)m_element
) TextElement();
507 int Equals(const Element
& other
) const
509 return Collate(*this, other
) == 0;
512 // are the values equal, case insenstitive for text
513 int EqualsI(const Element
& other
) const
515 return Collate(*this, other
, true) == 0;
518 static int Collate(const Element
& a
, const Element
& b
, bool insensitive
=false);
520 class ConversionException
: public RuntimeException
523 ConversionException(const char* message
)
524 : RuntimeException("conversion", message
)
535 inline const NumberElement
TextElement::ToNumber() const
538 memcpy(buffer
, m_p
, std::min(m_len
, sizeof(buffer
)-1));
539 buffer
[std::min(m_len
, sizeof(buffer
)-1)] = 0; // null terminate
540 return NumberElement(atof(buffer
));
545 long ElementBase::ToLong() const
547 double d
= ToNumber();
552 const KeywordElement
ElementBase::ToKeyword() const
554 throw Element::ConversionException("Cannot convert value to a keyword");
558 const ErrorElement
ElementBase::ToError() const
560 throw Element::ConversionException("Cannot convert value to a error");
564 const NumberElement
ElementBase::ToNumber() const
566 throw Element::ConversionException("Cannot convert value to a number");
570 const Element
ElementBase::ConvertTo(MA
* ma
, ElementType type
) const
582 throw Element::ConversionException("Cannot convert value.");
587 int Element::Collate(const Element
& aIn
, const Element
& bIn
, bool bInsensitive
)
589 const ElementBase
& a
= *(ElementBase
*)aIn
.m_element
;
590 const ElementBase
& b
= *(ElementBase
*)bIn
.m_element
;
592 ElementType aType
= a
.GetType();
593 ElementType bType
= b
.GetType();
597 } else if (aType
> bType
) {
604 double dbl_a
= ((NumberElement
&)a
);
605 double dbl_b
= ((NumberElement
&)b
);
606 return cmp(dbl_a
, dbl_b
);
610 return TextElement::CompareI((TextElement
&)a
, (TextElement
&)b
);
613 return TextElement::Compare((TextElement
&)a
, (TextElement
&)b
);
616 return cmp(((TimeElement
&)a
).time
, ((TimeElement
&)b
).time
);
618 return TextElement::CompareI(((ErrorElement
&)a
).TypeId(), ((ErrorElement
&)b
).TypeId());
620 return cmp(((KeywordElement
&)a
).GetIdAtom(), ((KeywordElement
&)b
).GetIdAtom());
627 #pragma pack(pop, r1)
629 #endif // FABRIC_ELEMENT_H