2015-12-23 8 views
8

AFAIK इसके लिए कोई अंतर्निहित कार्य नहीं है। वेब पर खोजते हुए मुझे यह function मिला और यह मेरे लिए काम करता है, लेकिन मैं इसे असेंबली के बाद उपयोग नहीं करना पसंद करता हूं और मैं समझ नहीं पा रहा हूं कि यह क्या कर रहा है। तो मैं इस समारोह है कि भी काम करता है लिखा है:मैं किसी भी प्रकार के चर सेट के तत्वों की संख्या कैसे प्राप्त कर सकता हूं?

function Cardinality(const PSet: PByteArray; 
    const SizeOfSet(*in bytes*): Integer): Integer; 
const 
    Masks: array[0..7] of Byte = (1, 2, 4, 8, 16, 32, 64, 128); 
var 
    I, J: Integer; 
begin 
    Result := 0; 
    for I := 0 to SizeOfSet - 1 do 
    for J := 0 to 7 do 
     if (PSet^[I] and Masks[J]) > 0 then 
     Inc(Result); 
end; 

अब, मुझे पता है कि अगर मैं इस समारोह पर भरोसा कर सकते हैं? या शायद सेट डेटा प्रकार के पीछे एक चाल है और यही कारण है कि डेल्फी के लिए अंतर्निहित विधि नहीं है।

लेकिन if मेरी समारोह विश्वसनीय है then मैं इसे कैसे सुधार सकते हैं:

  1. पास इसे करने के लिए स्थिरांक
  2. एक प्रकार की जाँच करें और सुनिश्चित करें कि एक सेट समारोह
  3. पास करने के लिए पारित हो जाता है बनाने के इसका पता
  4. के बजाय मूल्य SizeOfSet पैरामीटर से छुटकारा

मैं इसे Cardinality(@AnySet, SizeOf(TAnySet)) के बजाय Cardinality(AnySet) पर कॉल करना चाहता हूं।

वैसे, मुझे इसे XE और XE5 दोनों में संकलित करने की आवश्यकता है।

उत्तर

5

आप जेनरिक और आरटीटीआई के साथ इसे कार्यान्वित कर सकते हैं। इसलिए जैसा:

uses 
    SysUtils, TypInfo; 

type 
    ERuntimeTypeError = class(Exception); 

    TSet<T> = class 
    strict private 
    class function TypeInfo: PTypeInfo; inline; static; 
    public 
    class function IsSet: Boolean; static; 
    class function Cardinality(const Value: T): Integer; static; 
    end; 

const 
    Masks: array[0..7] of Byte = (1, 2, 4, 8, 16, 32, 64, 128); 

implementation 

{ TSet<T> } 

class function TSet<T>.TypeInfo: PTypeInfo; 
begin 
    Result := System.TypeInfo(T); 
end; 

class function TSet<T>.IsSet: Boolean; 
begin 
    Result := TypeInfo.Kind=tkSet; 
end; 

function GetCardinality(const PSet: PByteArray; 
    const SizeOfSet(*in bytes*): Integer): Integer; inline; 
var 
    I, J: Integer; 
begin 
    Result := 0; 
    for I := 0 to SizeOfSet - 1 do 
    for J := 0 to 7 do 
     if (PSet^[I] and Masks[J]) > 0 then 
     Inc(Result); 
end; 

class function TSet<T>.Cardinality(const Value: T): Integer; 
var 
    EnumTypeData: PTypeData; 
begin 
    if not IsSet then 
    raise ERuntimeTypeError.Create('Invalid type in TSet<T>, T must be a set'); 
    Result := GetCardinality(PByteArray(@Value), SizeOf(Value)); 
end; 

उपयोग:

Writeln(TSet<SomeSet>.Cardinality(Value)); 
+0

धन्यवाद, लेकिन XE यह संकलन नहीं करता है: ** E2506 इंटरफ़ेस अनुभाग में घोषित पैरामीटर प्रकार के तरीके को स्थानीय प्रतीक 'GetCardinality' ** का उपयोग नहीं करना चाहिए। तो मुझे क्लास फ़ंक्शन के रूप में 'GetCardinality' को परिभाषित करना होगा। 'मास्क' के बारे में वही समस्या। उन परिवर्तनों के बाद यह चलता है और ठीक काम करता है। – saastn

+1

हाँ, यह पुराने कंपाइलर्स में एक कंपाइलर दोष है। यदि आप चाहें तो मैन्युअल रूप से उस फ़ंक्शन को इनलाइन कर सकते हैं। वैसे भी, अवधारणा ध्वनि है। –

2

में डेल्फी के पुराने संस्करण आप ऐसा कर सकते हैं:

function Card(ASet: TSet): Integer; 
var 
    k: TSetElement; 
begin 
    Result := 0; 
    for k in ASet do Inc(Result); 
end; 
+0

क्या आपके कोड में परिभाषित सामान्य प्रकार या प्रकार 'TSet' और 'TSetElement' हैं? – saastn

संबंधित मुद्दे

 संबंधित मुद्दे