forked from zhurui/management
515 lines
17 KiB
C++
515 lines
17 KiB
C++
/*********************************************************************
|
|
* NAN - Native Abstractions for Node.js
|
|
*
|
|
* Copyright (c) 2018 NAN contributors
|
|
*
|
|
* MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
|
|
********************************************************************/
|
|
|
|
#ifndef NAN_CALLBACKS_12_INL_H_
|
|
#define NAN_CALLBACKS_12_INL_H_
|
|
|
|
template<typename T>
|
|
class ReturnValue {
|
|
v8::ReturnValue<T> value_;
|
|
|
|
public:
|
|
template <class S>
|
|
explicit inline ReturnValue(const v8::ReturnValue<S> &value) :
|
|
value_(value) {}
|
|
template <class S>
|
|
explicit inline ReturnValue(const ReturnValue<S>& that)
|
|
: value_(that.value_) {
|
|
TYPE_CHECK(T, S);
|
|
}
|
|
|
|
// Handle setters
|
|
template <typename S> inline void Set(const v8::Local<S> &handle) {
|
|
TYPE_CHECK(T, S);
|
|
value_.Set(handle);
|
|
}
|
|
|
|
template <typename S> inline void Set(const Global<S> &handle) {
|
|
TYPE_CHECK(T, S);
|
|
#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
|
|
(V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && \
|
|
(V8_MINOR_VERSION > 5 || (V8_MINOR_VERSION == 5 && \
|
|
defined(V8_BUILD_NUMBER) && V8_BUILD_NUMBER >= 8))))
|
|
value_.Set(handle);
|
|
#else
|
|
value_.Set(*reinterpret_cast<const v8::Persistent<S>*>(&handle));
|
|
const_cast<Global<S> &>(handle).Reset();
|
|
#endif
|
|
}
|
|
|
|
// Fast primitive setters
|
|
inline void Set(bool value) {
|
|
TYPE_CHECK(T, v8::Boolean);
|
|
value_.Set(value);
|
|
}
|
|
|
|
inline void Set(double i) {
|
|
TYPE_CHECK(T, v8::Number);
|
|
value_.Set(i);
|
|
}
|
|
|
|
inline void Set(int32_t i) {
|
|
TYPE_CHECK(T, v8::Integer);
|
|
value_.Set(i);
|
|
}
|
|
|
|
inline void Set(uint32_t i) {
|
|
TYPE_CHECK(T, v8::Integer);
|
|
value_.Set(i);
|
|
}
|
|
|
|
// Fast JS primitive setters
|
|
inline void SetNull() {
|
|
TYPE_CHECK(T, v8::Primitive);
|
|
value_.SetNull();
|
|
}
|
|
|
|
inline void SetUndefined() {
|
|
TYPE_CHECK(T, v8::Primitive);
|
|
value_.SetUndefined();
|
|
}
|
|
|
|
inline void SetEmptyString() {
|
|
TYPE_CHECK(T, v8::String);
|
|
value_.SetEmptyString();
|
|
}
|
|
|
|
// Convenience getter for isolate
|
|
inline v8::Isolate *GetIsolate() const {
|
|
return value_.GetIsolate();
|
|
}
|
|
|
|
// Pointer setter: Uncompilable to prevent inadvertent misuse.
|
|
template<typename S>
|
|
inline void Set(S *whatever) { TYPE_CHECK(S*, v8::Primitive); }
|
|
};
|
|
|
|
template<typename T>
|
|
class FunctionCallbackInfo {
|
|
const v8::FunctionCallbackInfo<T> &info_;
|
|
const v8::Local<v8::Value> data_;
|
|
|
|
public:
|
|
explicit inline FunctionCallbackInfo(
|
|
const v8::FunctionCallbackInfo<T> &info
|
|
, v8::Local<v8::Value> data) :
|
|
info_(info)
|
|
, data_(data) {}
|
|
|
|
inline ReturnValue<T> GetReturnValue() const {
|
|
return ReturnValue<T>(info_.GetReturnValue());
|
|
}
|
|
|
|
#if NODE_MAJOR_VERSION < 10
|
|
inline v8::Local<v8::Function> Callee() const { return info_.Callee(); }
|
|
#endif
|
|
inline v8::Local<v8::Value> Data() const { return data_; }
|
|
inline v8::Local<v8::Object> Holder() const { return info_.Holder(); }
|
|
inline bool IsConstructCall() const { return info_.IsConstructCall(); }
|
|
inline int Length() const { return info_.Length(); }
|
|
inline v8::Local<v8::Value> operator[](int i) const { return info_[i]; }
|
|
inline v8::Local<v8::Object> This() const { return info_.This(); }
|
|
inline v8::Isolate *GetIsolate() const { return info_.GetIsolate(); }
|
|
|
|
|
|
protected:
|
|
static const int kHolderIndex = 0;
|
|
static const int kIsolateIndex = 1;
|
|
static const int kReturnValueDefaultValueIndex = 2;
|
|
static const int kReturnValueIndex = 3;
|
|
static const int kDataIndex = 4;
|
|
static const int kCalleeIndex = 5;
|
|
static const int kContextSaveIndex = 6;
|
|
static const int kArgsLength = 7;
|
|
|
|
private:
|
|
NAN_DISALLOW_ASSIGN_COPY_MOVE(FunctionCallbackInfo)
|
|
};
|
|
|
|
template<typename T>
|
|
class PropertyCallbackInfo {
|
|
const v8::PropertyCallbackInfo<T> &info_;
|
|
const v8::Local<v8::Value> data_;
|
|
|
|
public:
|
|
explicit inline PropertyCallbackInfo(
|
|
const v8::PropertyCallbackInfo<T> &info
|
|
, const v8::Local<v8::Value> data) :
|
|
info_(info)
|
|
, data_(data) {}
|
|
|
|
inline v8::Isolate* GetIsolate() const { return info_.GetIsolate(); }
|
|
inline v8::Local<v8::Value> Data() const { return data_; }
|
|
inline v8::Local<v8::Object> This() const { return info_.This(); }
|
|
inline v8::Local<v8::Object> Holder() const { return info_.Holder(); }
|
|
inline ReturnValue<T> GetReturnValue() const {
|
|
return ReturnValue<T>(info_.GetReturnValue());
|
|
}
|
|
|
|
protected:
|
|
static const int kHolderIndex = 0;
|
|
static const int kIsolateIndex = 1;
|
|
static const int kReturnValueDefaultValueIndex = 2;
|
|
static const int kReturnValueIndex = 3;
|
|
static const int kDataIndex = 4;
|
|
static const int kThisIndex = 5;
|
|
static const int kArgsLength = 6;
|
|
|
|
private:
|
|
NAN_DISALLOW_ASSIGN_COPY_MOVE(PropertyCallbackInfo)
|
|
};
|
|
|
|
namespace imp {
|
|
static
|
|
void FunctionCallbackWrapper(const v8::FunctionCallbackInfo<v8::Value> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
FunctionCallback callback = reinterpret_cast<FunctionCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kFunctionIndex).As<v8::External>()->Value()));
|
|
FunctionCallbackInfo<v8::Value>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
callback(cbinfo);
|
|
}
|
|
|
|
typedef void (*NativeFunction)(const v8::FunctionCallbackInfo<v8::Value> &);
|
|
|
|
#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION
|
|
static
|
|
void GetterCallbackWrapper(
|
|
v8::Local<v8::Name> property
|
|
, const v8::PropertyCallbackInfo<v8::Value> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Value>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
GetterCallback callback = reinterpret_cast<GetterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kGetterIndex).As<v8::External>()->Value()));
|
|
callback(property.As<v8::String>(), cbinfo);
|
|
}
|
|
|
|
typedef void (*NativeGetter)
|
|
(v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value> &);
|
|
|
|
static
|
|
void SetterCallbackWrapper(
|
|
v8::Local<v8::Name> property
|
|
, v8::Local<v8::Value> value
|
|
, const v8::PropertyCallbackInfo<void> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<void>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
SetterCallback callback = reinterpret_cast<SetterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kSetterIndex).As<v8::External>()->Value()));
|
|
callback(property.As<v8::String>(), value, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativeSetter)(
|
|
v8::Local<v8::Name>
|
|
, v8::Local<v8::Value>
|
|
, const v8::PropertyCallbackInfo<void> &);
|
|
#else
|
|
static
|
|
void GetterCallbackWrapper(
|
|
v8::Local<v8::String> property
|
|
, const v8::PropertyCallbackInfo<v8::Value> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Value>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
GetterCallback callback = reinterpret_cast<GetterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kGetterIndex).As<v8::External>()->Value()));
|
|
callback(property, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativeGetter)
|
|
(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value> &);
|
|
|
|
static
|
|
void SetterCallbackWrapper(
|
|
v8::Local<v8::String> property
|
|
, v8::Local<v8::Value> value
|
|
, const v8::PropertyCallbackInfo<void> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<void>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
SetterCallback callback = reinterpret_cast<SetterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kSetterIndex).As<v8::External>()->Value()));
|
|
callback(property, value, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativeSetter)(
|
|
v8::Local<v8::String>
|
|
, v8::Local<v8::Value>
|
|
, const v8::PropertyCallbackInfo<void> &);
|
|
#endif
|
|
|
|
#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION
|
|
static
|
|
void PropertyGetterCallbackWrapper(
|
|
v8::Local<v8::Name> property
|
|
, const v8::PropertyCallbackInfo<v8::Value> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Value>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
PropertyGetterCallback callback = reinterpret_cast<PropertyGetterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kPropertyGetterIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(property.As<v8::String>(), cbinfo);
|
|
}
|
|
|
|
typedef void (*NativePropertyGetter)
|
|
(v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value> &);
|
|
|
|
static
|
|
void PropertySetterCallbackWrapper(
|
|
v8::Local<v8::Name> property
|
|
, v8::Local<v8::Value> value
|
|
, const v8::PropertyCallbackInfo<v8::Value> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Value>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
PropertySetterCallback callback = reinterpret_cast<PropertySetterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kPropertySetterIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(property.As<v8::String>(), value, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativePropertySetter)(
|
|
v8::Local<v8::Name>
|
|
, v8::Local<v8::Value>
|
|
, const v8::PropertyCallbackInfo<v8::Value> &);
|
|
|
|
static
|
|
void PropertyEnumeratorCallbackWrapper(
|
|
const v8::PropertyCallbackInfo<v8::Array> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Array>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
PropertyEnumeratorCallback callback =
|
|
reinterpret_cast<PropertyEnumeratorCallback>(reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kPropertyEnumeratorIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(cbinfo);
|
|
}
|
|
|
|
typedef void (*NativePropertyEnumerator)
|
|
(const v8::PropertyCallbackInfo<v8::Array> &);
|
|
|
|
static
|
|
void PropertyDeleterCallbackWrapper(
|
|
v8::Local<v8::Name> property
|
|
, const v8::PropertyCallbackInfo<v8::Boolean> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Boolean>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
PropertyDeleterCallback callback = reinterpret_cast<PropertyDeleterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kPropertyDeleterIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(property.As<v8::String>(), cbinfo);
|
|
}
|
|
|
|
typedef void (NativePropertyDeleter)
|
|
(v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Boolean> &);
|
|
|
|
static
|
|
void PropertyQueryCallbackWrapper(
|
|
v8::Local<v8::Name> property
|
|
, const v8::PropertyCallbackInfo<v8::Integer> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Integer>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
PropertyQueryCallback callback = reinterpret_cast<PropertyQueryCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kPropertyQueryIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(property.As<v8::String>(), cbinfo);
|
|
}
|
|
|
|
typedef void (*NativePropertyQuery)
|
|
(v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Integer> &);
|
|
#else
|
|
static
|
|
void PropertyGetterCallbackWrapper(
|
|
v8::Local<v8::String> property
|
|
, const v8::PropertyCallbackInfo<v8::Value> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Value>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
PropertyGetterCallback callback = reinterpret_cast<PropertyGetterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kPropertyGetterIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(property, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativePropertyGetter)
|
|
(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value> &);
|
|
|
|
static
|
|
void PropertySetterCallbackWrapper(
|
|
v8::Local<v8::String> property
|
|
, v8::Local<v8::Value> value
|
|
, const v8::PropertyCallbackInfo<v8::Value> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Value>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
PropertySetterCallback callback = reinterpret_cast<PropertySetterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kPropertySetterIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(property, value, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativePropertySetter)(
|
|
v8::Local<v8::String>
|
|
, v8::Local<v8::Value>
|
|
, const v8::PropertyCallbackInfo<v8::Value> &);
|
|
|
|
static
|
|
void PropertyEnumeratorCallbackWrapper(
|
|
const v8::PropertyCallbackInfo<v8::Array> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Array>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
PropertyEnumeratorCallback callback =
|
|
reinterpret_cast<PropertyEnumeratorCallback>(reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kPropertyEnumeratorIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(cbinfo);
|
|
}
|
|
|
|
typedef void (*NativePropertyEnumerator)
|
|
(const v8::PropertyCallbackInfo<v8::Array> &);
|
|
|
|
static
|
|
void PropertyDeleterCallbackWrapper(
|
|
v8::Local<v8::String> property
|
|
, const v8::PropertyCallbackInfo<v8::Boolean> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Boolean>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
PropertyDeleterCallback callback = reinterpret_cast<PropertyDeleterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kPropertyDeleterIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(property, cbinfo);
|
|
}
|
|
|
|
typedef void (NativePropertyDeleter)
|
|
(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Boolean> &);
|
|
|
|
static
|
|
void PropertyQueryCallbackWrapper(
|
|
v8::Local<v8::String> property
|
|
, const v8::PropertyCallbackInfo<v8::Integer> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Integer>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
PropertyQueryCallback callback = reinterpret_cast<PropertyQueryCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kPropertyQueryIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(property, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativePropertyQuery)
|
|
(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Integer> &);
|
|
#endif
|
|
|
|
static
|
|
void IndexGetterCallbackWrapper(
|
|
uint32_t index, const v8::PropertyCallbackInfo<v8::Value> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Value>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
IndexGetterCallback callback = reinterpret_cast<IndexGetterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kIndexPropertyGetterIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(index, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativeIndexGetter)
|
|
(uint32_t, const v8::PropertyCallbackInfo<v8::Value> &);
|
|
|
|
static
|
|
void IndexSetterCallbackWrapper(
|
|
uint32_t index
|
|
, v8::Local<v8::Value> value
|
|
, const v8::PropertyCallbackInfo<v8::Value> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Value>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
IndexSetterCallback callback = reinterpret_cast<IndexSetterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kIndexPropertySetterIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(index, value, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativeIndexSetter)(
|
|
uint32_t
|
|
, v8::Local<v8::Value>
|
|
, const v8::PropertyCallbackInfo<v8::Value> &);
|
|
|
|
static
|
|
void IndexEnumeratorCallbackWrapper(
|
|
const v8::PropertyCallbackInfo<v8::Array> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Array>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
IndexEnumeratorCallback callback = reinterpret_cast<IndexEnumeratorCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(
|
|
kIndexPropertyEnumeratorIndex).As<v8::External>()->Value()));
|
|
callback(cbinfo);
|
|
}
|
|
|
|
typedef void (*NativeIndexEnumerator)
|
|
(const v8::PropertyCallbackInfo<v8::Array> &);
|
|
|
|
static
|
|
void IndexDeleterCallbackWrapper(
|
|
uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Boolean>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
IndexDeleterCallback callback = reinterpret_cast<IndexDeleterCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kIndexPropertyDeleterIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(index, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativeIndexDeleter)
|
|
(uint32_t, const v8::PropertyCallbackInfo<v8::Boolean> &);
|
|
|
|
static
|
|
void IndexQueryCallbackWrapper(
|
|
uint32_t index, const v8::PropertyCallbackInfo<v8::Integer> &info) {
|
|
v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
|
|
PropertyCallbackInfo<v8::Integer>
|
|
cbinfo(info, obj->GetInternalField(kDataIndex));
|
|
IndexQueryCallback callback = reinterpret_cast<IndexQueryCallback>(
|
|
reinterpret_cast<intptr_t>(
|
|
obj->GetInternalField(kIndexPropertyQueryIndex)
|
|
.As<v8::External>()->Value()));
|
|
callback(index, cbinfo);
|
|
}
|
|
|
|
typedef void (*NativeIndexQuery)
|
|
(uint32_t, const v8::PropertyCallbackInfo<v8::Integer> &);
|
|
} // end of namespace imp
|
|
|
|
#endif // NAN_CALLBACKS_12_INL_H_
|