<commit_before>#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cstdio> // debug

#ifdef _MSC_VER
	#include "win32\types.h"
#endif

#include "ColumnString.h"

// Pre-declare local functions
ColumnDef GetTypeFromArray(size_t ref, Allocator& alloc);

ColumnDef GetTypeFromArray(size_t ref, Allocator& alloc) {
	const uint8_t* const header = (uint8_t*)alloc.Translate(ref);
	const bool isNode = (header[0] & 0x80) != 0;
	const bool hasRefs  = (header[0] & 0x40) != 0;

	if (isNode) return COLUMN_NODE;
	else if (hasRefs) return COLUMN_HASREFS;
	else return COLUMN_NORMAL;
}

AdaptiveStringColumn::AdaptiveStringColumn(Allocator& alloc) {
	m_array = new ArrayString(NULL, 0, alloc);
}

AdaptiveStringColumn::AdaptiveStringColumn(size_t ref, Array* parent, size_t pndx, Allocator& alloc) {
	const ColumnDef type = GetTypeFromArray(ref, alloc);
	if (type == COLUMN_NODE) {
		m_array = new Array(ref, parent, pndx, alloc);
	}
	else if (type == COLUMN_HASREFS) {
		m_array = new ArrayStringLong(ref, parent, pndx, alloc);
	}
	else {
		m_array = new ArrayString(ref, parent, pndx, alloc);
	}
}

AdaptiveStringColumn::AdaptiveStringColumn(size_t ref, const Array* parent, size_t pndx, Allocator& alloc) {
	const ColumnDef type = GetTypeFromArray(ref, alloc);
	if (type == COLUMN_NODE) {
		m_array = new Array(ref, parent, pndx, alloc);
	}
	else if (type == COLUMN_HASREFS) {
		m_array = new ArrayStringLong(ref, parent, pndx, alloc);
	}
	else {
		m_array = new ArrayString(ref, parent, pndx, alloc);
	}
}

AdaptiveStringColumn::~AdaptiveStringColumn() {
	delete m_array;
}

void AdaptiveStringColumn::Destroy() {
	if (IsNode()) m_array->Destroy();
	else if (IsLongStrings()) {
		((ArrayStringLong*)m_array)->Destroy();
	}
	else ((ArrayString*)m_array)->Destroy();
}

void AdaptiveStringColumn::UpdateRef(size_t ref) {
	assert(GetTypeFromArray(ref, m_array->GetAllocator()) == COLUMN_NODE); // Can only be called when creating node

	if (IsNode()) m_array->UpdateRef(ref);
	else {
		Array* parent = m_array->GetParent();
		size_t pndx   = m_array->GetParentNdx();

		// Replace the string array with int array for node
		Array* array = new Array(ref, parent, pndx, m_array->GetAllocator());
		delete m_array;
		m_array = array;

		// Update ref in parent
		if (parent) parent->Set(pndx, m_array->GetRef());
	}
}

bool AdaptiveStringColumn::IsEmpty() const {
	if (IsNode()) {
		const Array offsets = NodeGetOffsets();
		return offsets.IsEmpty();
	}
	else if (IsLongStrings()) {
		return ((ArrayStringLong*)m_array)->IsEmpty();
	}
	else {
		return ((ArrayString*)m_array)->IsEmpty();
	}
}

size_t AdaptiveStringColumn::Size() const {
	if (IsNode())  {
		const Array offsets = NodeGetOffsets();
		const size_t size = offsets.IsEmpty() ? 0 : (size_t)offsets.Back();
		return size;
	}
	else if (IsLongStrings()) {
		return ((ArrayStringLong*)m_array)->Size();
	}
	else {
		return ((ArrayString*)m_array)->Size();
	}
}

void AdaptiveStringColumn::Clear() {
	if (m_array->IsNode()) {
		// Revert to string array
		m_array->Destroy();
		Array* array = new ArrayString(m_array->GetParent(), m_array->GetParentNdx(), m_array->GetAllocator());
		delete m_array;
		m_array = array;
	}
	else if (IsLongStrings()) {
		((ArrayStringLong*)m_array)->Clear();
	}
	else ((ArrayString*)m_array)->Clear();
}

const char* AdaptiveStringColumn::Get(size_t ndx) const {
	assert(ndx < Size());
	return TreeGet<const char*, AdaptiveStringColumn>(ndx);
}

bool AdaptiveStringColumn::Set(size_t ndx, const char* value) {
	assert(ndx < Size());
	return TreeSet<const char*, AdaptiveStringColumn>(ndx, value);
}

bool AdaptiveStringColumn::Add(const char* value) {
	return Insert(Size(), value);
}

bool AdaptiveStringColumn::Insert(size_t ndx, const char* value) {
	assert(ndx <= Size());
	return TreeInsert<const char*, AdaptiveStringColumn>(ndx, value);
}

void AdaptiveStringColumn::Delete(size_t ndx) {
	assert(ndx < Size());
	TreeDelete<const char*, AdaptiveStringColumn>(ndx);
}

size_t AdaptiveStringColumn::Find(const char* value, size_t, size_t) const {
	assert(value);
	return TreeFind<const char*, AdaptiveStringColumn>(value, 0, -1);
}

void AdaptiveStringColumn::FindAll(Array &result, const char* value, size_t start, size_t end) const {
	assert(value);
	TreeFindAll<const char*, AdaptiveStringColumn>(result, value, 0, start, end);
}

const char* AdaptiveStringColumn::LeafGet(size_t ndx) const {
	if (IsLongStrings()) {
		return ((ArrayStringLong*)m_array)->Get(ndx);
	}
	else {
		return ((ArrayString*)m_array)->Get(ndx);
	}
}

bool AdaptiveStringColumn::LeafSet(size_t ndx, const char* value) {
	// Easy to set if the strings fit
	const size_t len = strlen(value);
	if (IsLongStrings()) {
		((ArrayStringLong*)m_array)->Set(ndx, value, len);
		return true;
	}
	else if (len < 16) {
		return ((ArrayString*)m_array)->Set(ndx, value);
	}

	// Replace string array with long string array
	ArrayStringLong* const newarray = new ArrayStringLong((Array*)NULL, 0, m_array->GetAllocator());

	// Copy strings to new array
	ArrayString* const oldarray = (ArrayString*)m_array;
	for (size_t i = 0; i < oldarray->Size(); ++i) {
		newarray->Add(oldarray->Get(i));
	}
	newarray->Set(ndx, value, len);

	// Update parent to point to new array
	Array* const parent = oldarray->GetParent();
	if (parent) {
		const size_t pndx = oldarray->GetParentNdx();
		parent->Set(pndx, newarray->GetRef());
		newarray->SetParent(parent, pndx);
	}

	// Replace string array with long string array
	m_array = (Array*)newarray;
	oldarray->Destroy();
	delete oldarray;

	return true;}

bool AdaptiveStringColumn::LeafInsert(size_t ndx, const char* value) {
	// Easy to insert if the strings fit
	const size_t len = strlen(value);
	if (IsLongStrings()) {
		((ArrayStringLong*)m_array)->Insert(ndx, value, len);
		return true;
	}
	else if (len < 16) {
		return ((ArrayString*)m_array)->Insert(ndx, value);
	}

	// Replace string array with long string array
	ArrayStringLong* const newarray = new ArrayStringLong((Array*)NULL, 0, m_array->GetAllocator());

	// Copy strings to new array
	ArrayString* const oldarray = (ArrayString*)m_array;
	for (size_t i = 0; i < oldarray->Size(); ++i) {
		newarray->Add(oldarray->Get(i));
	}
	newarray->Insert(ndx, value, len);

	// Update parent to point to new array
	Array* const parent = oldarray->GetParent();
	if (parent) {
		const size_t pndx = oldarray->GetParentNdx();
		parent->Set(pndx, newarray->GetRef());
		newarray->SetParent(parent, pndx);
	}

	// Replace string array with long string array
	m_array = (Array*)newarray;
	oldarray->Destroy();
	delete oldarray;

	return true;
}

size_t AdaptiveStringColumn::LeafFind(const char* value, size_t start, size_t end) const {
	if (IsLongStrings()) {
		return ((ArrayStringLong*)m_array)->Find(value, start, end);
	}
	else {
		return ((ArrayString*)m_array)->Find(value, start, end);
	}
}

void AdaptiveStringColumn::LeafFindAll(Array &result, const char* value, size_t add_offset, size_t start, size_t end) const {
	if (IsLongStrings()) {
		return ((ArrayStringLong*)m_array)->FindAll(result, value, add_offset, start, end);
	}
	else {
		return ((ArrayString*)m_array)->FindAll(result, value, add_offset, start, end);
	}
}

void AdaptiveStringColumn::LeafDelete(size_t ndx) {
	if (IsLongStrings()) {
		((ArrayStringLong*)m_array)->Delete(ndx);
	}
	else {
		((ArrayString*)m_array)->Delete(ndx);
	}
}

bool AdaptiveStringColumn::FindKeyPos(const char* target, size_t& pos) const {
	const int len = (int)Size();
	bool found = false;
	ssize_t low  = -1;
	ssize_t high = len;

	// Binary search based on:
	// http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary
	// Finds position of closest value BIGGER OR EQUAL to the target (for
	// lookups in indexes)
	while (high - low > 1) {
		const ssize_t probe = ((size_t)low + (size_t)high) >> 1;
		const char* v = Get(probe);

		const int cmp = strcmp(v, target);

		if (cmp < 0) low  = probe;
		else {
			high = probe;
			if (cmp == 0) found = true;
		}
	}

	pos = high;
	return found;
}

bool AdaptiveStringColumn::AutoEnumerate(size_t& ref_keys, size_t& ref_values) const {
	AdaptiveStringColumn keys(m_array->GetAllocator());

	// Generate list of unique values (keys)
	const size_t count = Size();
	for (size_t i = 0; i < count; ++i) {
		const char* v = Get(i);

		// Insert keys in sorted order, ignoring duplicates
		size_t pos;
		if (!keys.FindKeyPos(v, pos)) {
			keys.Insert(pos, v);
		}
	}

	// Don't bpther auto enumerating if there are too few duplicates
	if (keys.Size() > (count / 2)) {
		keys.Destroy(); // cleanup
		return false;
	}

	// Generate enumerated list of entries
	Column values(m_array->GetAllocator());
	for (size_t i = 0; i < count; ++i) {
		const char* v = Get(i);

		size_t pos;
		const bool res = keys.FindKeyPos(v, pos);
		assert(res);

		values.Add(pos);
	}

	ref_keys   = keys.GetRef();
	ref_values = values.GetRef();
	return true;
}

#ifdef _DEBUG
#include <cstring> // strcmp()

bool AdaptiveStringColumn::Compare(const AdaptiveStringColumn& c) const {
	if (c.Size() != Size()) return false;

	for (size_t i = 0; i < Size(); ++i) {
		const char* s1 = Get(i);
		const char* s2 = c.Get(i);
		if (strcmp(s1, s2) != 0) return false;
	}

	return true;
}

void AdaptiveStringColumn::ToDot(FILE* f, bool) const {
	m_array->ToDot(f);
}

MemStats AdaptiveStringColumn::Stats() const {
	MemStats stats;

	if (m_array->IsNode()) {
		const Array refs = NodeGetRefs();

		for (size_t i = 0; i < refs.Size(); ++i) {
			const size_t r = (size_t)refs.Get(i);
			const AdaptiveStringColumn col(r);

			const MemStats m = col.Stats();
			stats.Add(m);
		}

		// Add node itself
		const MemStats m = m_array->Stats();
		stats.Add(m);
	}
	else if (IsLongStrings()) {
		const MemStats m = ((ArrayStringLong*)m_array)->Stats();
		stats.Add(m);
	}
	else {
		const MemStats m = ((ArrayString*)m_array)->Stats();
		stats.Add(m);
	}

	return stats;
}

#endif //_DEBUG
<commit_msg>Fixed bug in AdaptiveStringColumn::Find<commit_after>#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cstdio> // debug

#ifdef _MSC_VER
	#include "win32\types.h"
#endif

#include "ColumnString.h"

// Pre-declare local functions
ColumnDef GetTypeFromArray(size_t ref, Allocator& alloc);

ColumnDef GetTypeFromArray(size_t ref, Allocator& alloc) {
	const uint8_t* const header = (uint8_t*)alloc.Translate(ref);
	const bool isNode = (header[0] & 0x80) != 0;
	const bool hasRefs  = (header[0] & 0x40) != 0;

	if (isNode) return COLUMN_NODE;
	else if (hasRefs) return COLUMN_HASREFS;
	else return COLUMN_NORMAL;
}

AdaptiveStringColumn::AdaptiveStringColumn(Allocator& alloc) {
	m_array = new ArrayString(NULL, 0, alloc);
}

AdaptiveStringColumn::AdaptiveStringColumn(size_t ref, Array* parent, size_t pndx, Allocator& alloc) {
	const ColumnDef type = GetTypeFromArray(ref, alloc);
	if (type == COLUMN_NODE) {
		m_array = new Array(ref, parent, pndx, alloc);
	}
	else if (type == COLUMN_HASREFS) {
		m_array = new ArrayStringLong(ref, parent, pndx, alloc);
	}
	else {
		m_array = new ArrayString(ref, parent, pndx, alloc);
	}
}

AdaptiveStringColumn::AdaptiveStringColumn(size_t ref, const Array* parent, size_t pndx, Allocator& alloc) {
	const ColumnDef type = GetTypeFromArray(ref, alloc);
	if (type == COLUMN_NODE) {
		m_array = new Array(ref, parent, pndx, alloc);
	}
	else if (type == COLUMN_HASREFS) {
		m_array = new ArrayStringLong(ref, parent, pndx, alloc);
	}
	else {
		m_array = new ArrayString(ref, parent, pndx, alloc);
	}
}

AdaptiveStringColumn::~AdaptiveStringColumn() {
	delete m_array;
}

void AdaptiveStringColumn::Destroy() {
	if (IsNode()) m_array->Destroy();
	else if (IsLongStrings()) {
		((ArrayStringLong*)m_array)->Destroy();
	}
	else ((ArrayString*)m_array)->Destroy();
}

void AdaptiveStringColumn::UpdateRef(size_t ref) {
	assert(GetTypeFromArray(ref, m_array->GetAllocator()) == COLUMN_NODE); // Can only be called when creating node

	if (IsNode()) m_array->UpdateRef(ref);
	else {
		Array* parent = m_array->GetParent();
		size_t pndx   = m_array->GetParentNdx();

		// Replace the string array with int array for node
		Array* array = new Array(ref, parent, pndx, m_array->GetAllocator());
		delete m_array;
		m_array = array;

		// Update ref in parent
		if (parent) parent->Set(pndx, m_array->GetRef());
	}
}

bool AdaptiveStringColumn::IsEmpty() const {
	if (IsNode()) {
		const Array offsets = NodeGetOffsets();
		return offsets.IsEmpty();
	}
	else if (IsLongStrings()) {
		return ((ArrayStringLong*)m_array)->IsEmpty();
	}
	else {
		return ((ArrayString*)m_array)->IsEmpty();
	}
}

size_t AdaptiveStringColumn::Size() const {
	if (IsNode())  {
		const Array offsets = NodeGetOffsets();
		const size_t size = offsets.IsEmpty() ? 0 : (size_t)offsets.Back();
		return size;
	}
	else if (IsLongStrings()) {
		return ((ArrayStringLong*)m_array)->Size();
	}
	else {
		return ((ArrayString*)m_array)->Size();
	}
}

void AdaptiveStringColumn::Clear() {
	if (m_array->IsNode()) {
		// Revert to string array
		m_array->Destroy();
		Array* array = new ArrayString(m_array->GetParent(), m_array->GetParentNdx(), m_array->GetAllocator());
		delete m_array;
		m_array = array;
	}
	else if (IsLongStrings()) {
		((ArrayStringLong*)m_array)->Clear();
	}
	else ((ArrayString*)m_array)->Clear();
}

const char* AdaptiveStringColumn::Get(size_t ndx) const {
	assert(ndx < Size());
	return TreeGet<const char*, AdaptiveStringColumn>(ndx);
}

bool AdaptiveStringColumn::Set(size_t ndx, const char* value) {
	assert(ndx < Size());
	return TreeSet<const char*, AdaptiveStringColumn>(ndx, value);
}

bool AdaptiveStringColumn::Add(const char* value) {
	return Insert(Size(), value);
}

bool AdaptiveStringColumn::Insert(size_t ndx, const char* value) {
	assert(ndx <= Size());
	return TreeInsert<const char*, AdaptiveStringColumn>(ndx, value);
}

void AdaptiveStringColumn::Delete(size_t ndx) {
	assert(ndx < Size());
	TreeDelete<const char*, AdaptiveStringColumn>(ndx);
}

size_t AdaptiveStringColumn::Find(const char* value, size_t start, size_t end) const {
	assert(value);
	return TreeFind<const char*, AdaptiveStringColumn>(value, start, end);
}

void AdaptiveStringColumn::FindAll(Array &result, const char* value, size_t start, size_t end) const {
	assert(value);
	TreeFindAll<const char*, AdaptiveStringColumn>(result, value, 0, start, end);
}

const char* AdaptiveStringColumn::LeafGet(size_t ndx) const {
	if (IsLongStrings()) {
		return ((ArrayStringLong*)m_array)->Get(ndx);
	}
	else {
		return ((ArrayString*)m_array)->Get(ndx);
	}
}

bool AdaptiveStringColumn::LeafSet(size_t ndx, const char* value) {
	// Easy to set if the strings fit
	const size_t len = strlen(value);
	if (IsLongStrings()) {
		((ArrayStringLong*)m_array)->Set(ndx, value, len);
		return true;
	}
	else if (len < 16) {
		return ((ArrayString*)m_array)->Set(ndx, value);
	}

	// Replace string array with long string array
	ArrayStringLong* const newarray = new ArrayStringLong((Array*)NULL, 0, m_array->GetAllocator());

	// Copy strings to new array
	ArrayString* const oldarray = (ArrayString*)m_array;
	for (size_t i = 0; i < oldarray->Size(); ++i) {
		newarray->Add(oldarray->Get(i));
	}
	newarray->Set(ndx, value, len);

	// Update parent to point to new array
	Array* const parent = oldarray->GetParent();
	if (parent) {
		const size_t pndx = oldarray->GetParentNdx();
		parent->Set(pndx, newarray->GetRef());
		newarray->SetParent(parent, pndx);
	}

	// Replace string array with long string array
	m_array = (Array*)newarray;
	oldarray->Destroy();
	delete oldarray;

	return true;}

bool AdaptiveStringColumn::LeafInsert(size_t ndx, const char* value) {
	// Easy to insert if the strings fit
	const size_t len = strlen(value);
	if (IsLongStrings()) {
		((ArrayStringLong*)m_array)->Insert(ndx, value, len);
		return true;
	}
	else if (len < 16) {
		return ((ArrayString*)m_array)->Insert(ndx, value);
	}

	// Replace string array with long string array
	ArrayStringLong* const newarray = new ArrayStringLong((Array*)NULL, 0, m_array->GetAllocator());

	// Copy strings to new array
	ArrayString* const oldarray = (ArrayString*)m_array;
	for (size_t i = 0; i < oldarray->Size(); ++i) {
		newarray->Add(oldarray->Get(i));
	}
	newarray->Insert(ndx, value, len);

	// Update parent to point to new array
	Array* const parent = oldarray->GetParent();
	if (parent) {
		const size_t pndx = oldarray->GetParentNdx();
		parent->Set(pndx, newarray->GetRef());
		newarray->SetParent(parent, pndx);
	}

	// Replace string array with long string array
	m_array = (Array*)newarray;
	oldarray->Destroy();
	delete oldarray;

	return true;
}

size_t AdaptiveStringColumn::LeafFind(const char* value, size_t start, size_t end) const {
	if (IsLongStrings()) {
		return ((ArrayStringLong*)m_array)->Find(value, start, end);
	}
	else {
		return ((ArrayString*)m_array)->Find(value, start, end);
	}
}

void AdaptiveStringColumn::LeafFindAll(Array &result, const char* value, size_t add_offset, size_t start, size_t end) const {
	if (IsLongStrings()) {
		return ((ArrayStringLong*)m_array)->FindAll(result, value, add_offset, start, end);
	}
	else {
		return ((ArrayString*)m_array)->FindAll(result, value, add_offset, start, end);
	}
}

void AdaptiveStringColumn::LeafDelete(size_t ndx) {
	if (IsLongStrings()) {
		((ArrayStringLong*)m_array)->Delete(ndx);
	}
	else {
		((ArrayString*)m_array)->Delete(ndx);
	}
}

bool AdaptiveStringColumn::FindKeyPos(const char* target, size_t& pos) const {
	const int len = (int)Size();
	bool found = false;
	ssize_t low  = -1;
	ssize_t high = len;

	// Binary search based on:
	// http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary
	// Finds position of closest value BIGGER OR EQUAL to the target (for
	// lookups in indexes)
	while (high - low > 1) {
		const ssize_t probe = ((size_t)low + (size_t)high) >> 1;
		const char* v = Get(probe);

		const int cmp = strcmp(v, target);

		if (cmp < 0) low  = probe;
		else {
			high = probe;
			if (cmp == 0) found = true;
		}
	}

	pos = high;
	return found;
}

bool AdaptiveStringColumn::AutoEnumerate(size_t& ref_keys, size_t& ref_values) const {
	AdaptiveStringColumn keys(m_array->GetAllocator());

	// Generate list of unique values (keys)
	const size_t count = Size();
	for (size_t i = 0; i < count; ++i) {
		const char* v = Get(i);

		// Insert keys in sorted order, ignoring duplicates
		size_t pos;
		if (!keys.FindKeyPos(v, pos)) {
			keys.Insert(pos, v);
		}
	}

	// Don't bpther auto enumerating if there are too few duplicates
	if (keys.Size() > (count / 2)) {
		keys.Destroy(); // cleanup
		return false;
	}

	// Generate enumerated list of entries
	Column values(m_array->GetAllocator());
	for (size_t i = 0; i < count; ++i) {
		const char* v = Get(i);

		size_t pos;
		const bool res = keys.FindKeyPos(v, pos);
		assert(res);

		values.Add(pos);
	}

	ref_keys   = keys.GetRef();
	ref_values = values.GetRef();
	return true;
}

#ifdef _DEBUG
#include <cstring> // strcmp()

bool AdaptiveStringColumn::Compare(const AdaptiveStringColumn& c) const {
	if (c.Size() != Size()) return false;

	for (size_t i = 0; i < Size(); ++i) {
		const char* s1 = Get(i);
		const char* s2 = c.Get(i);
		if (strcmp(s1, s2) != 0) return false;
	}

	return true;
}

void AdaptiveStringColumn::ToDot(FILE* f, bool) const {
	m_array->ToDot(f);
}

MemStats AdaptiveStringColumn::Stats() const {
	MemStats stats;

	if (m_array->IsNode()) {
		const Array refs = NodeGetRefs();

		for (size_t i = 0; i < refs.Size(); ++i) {
			const size_t r = (size_t)refs.Get(i);
			const AdaptiveStringColumn col(r);

			const MemStats m = col.Stats();
			stats.Add(m);
		}

		// Add node itself
		const MemStats m = m_array->Stats();
		stats.Add(m);
	}
	else if (IsLongStrings()) {
		const MemStats m = ((ArrayStringLong*)m_array)->Stats();
		stats.Add(m);
	}
	else {
		const MemStats m = ((ArrayString*)m_array)->Stats();
		stats.Add(m);
	}

	return stats;
}

#endif //_DEBUG
<|endoftext|>


<commit_before>// Copyright(C) 2022 Intel Corporation
// Licensed under the MIT License

#include "dnnl_layernorm.h"
#include "dnnl_subgraph.h"
#include "dnnl_subgraph_primitive.h"

namespace onnxruntime {
namespace ort_dnnl {

DnnlLayerNorm::DnnlLayerNorm() {}

/*
Layer Normalization and Skip Layer Normalization implementation:
Layer Norm:
  Inputs:
    0) X - Input Tensor
    1) G - Gamma Tensor (Scaling factor in the LN formula)
    2) B - Bias Tensor (Shift value in the LN formula. Optional)
  Outputs:
    0) Y - Output Tensor
    1) M - Mean Tensor (Optional)
    2) I - Inverse std Tensor (Optional)

               +-----------+
(X) ---------->+           +----------> (Y)
               |           |
(G) ---------->+ LayerNorm +----------> (M)
               |           |
(B) ---------->+           +----------> (I)
               +-----------+

Skip Layer Norm:
  Inputs:
    0) X - Input Tensor
    1) S - Skip Tensor
    2) G - Gamma Tensor (Scaling factor in the LN formula)
    4) E - Beta Tensor (Shift value in the LN formula. Optional)
    4) B - Bias Tensor (Bias when adding X + S. Optional)
  Outputs:
    0) Y - Output Tensor
    1) M - Mean Tensor (Optional)
    2) I - Inverse std Tensor (Optional)

               +-----------+
(X) ---------->+           |                   +-----------+
               |           |   (X + S + B)     |           |
(S) ---------->+ BuildSLN  +------------------>+           +----------> (Y)
               |           |                   |           |
(B) ---------->+           |      (G) -------->+ LayerNorm +----------> (M)
               +-----------+                   |           |
                                  (E) -------->+           +----------> (I)
                                               |           |
                                               +-----------+

Attributes (epsilon)
*/
void DnnlLayerNorm::CreatePrimitive(DnnlSubgraphPrimitive& sp, DnnlNode& node) {

  // Get engine
  auto dnnl_engine = sp.GetEngine();

  // Make sure every input's dimension follows the spec
  ValidateDims(sp, node);

  // Optional input flag
  bool shift_exists = false;

  // Input positions
  int shift_pos, scale_pos;

  // Get src mem
  auto src_mem = sp.GetMemory(node.Input(IN_INPUT));
  auto src_md = src_mem.get_desc();

  // This contains the layer norm op and its parameters
  ln_components op_comps;
  if (node.OpType() == "SkipLayerNormalization") {

    // Check if shift is available
    shift_exists = node.Input(IN_BETA).Exists();

    // Fix positions for arguments
    shift_pos = IN_BETA;
    scale_pos = IN_SLN_GAMMA;

    // Build SLN and get modified mem
    src_mem = BuildSLN(sp, node, dnnl_engine);

  } else if (node.OpType() == "LayerNormalization") {

    // Check if shift is available
    shift_exists = node.Input(IN_LN_BIAS).Exists();

    // Fix positions for arguments
    shift_pos = IN_LN_BIAS;
    scale_pos = IN_LN_GAMMA;

    // Move the src to GPU if needed
    src_mem = sp.GetMemoryAndReshape(node.Input(IN_INPUT), src_mem.get_desc(), dnnl_engine);

  } else {
    ORT_THROW("Unknown LayerNormalization flavor");
  }

  // X = LayerNornm(X)
  // Check if we are training and need the extra outputs for backprop
  dnnl::prop_kind prop_kind;
#if 0 //defined(ENABLE_TRAINING)
  prop_kind = dnnl::prop_kind::forward_training;
#else
  prop_kind = dnnl::prop_kind::forward_inference;
#endif  // ENABLE_TRAINING

  // If beta is available use shift, else only scale
  dnnl::normalization_flags op_flags = dnnl::normalization_flags::use_scale;
  if (shift_exists) {
    op_flags |= dnnl::normalization_flags::use_shift;
  }

  // Get epsilon to avoid zero division
  float epsilon = GetEpsilon(node);
  // Operation desciptor
  auto lnorm_desc = dnnl::layer_normalization_forward::desc(prop_kind, src_md, epsilon, op_flags);
  // Primitive desciptor
  auto lnorm_pd = dnnl::layer_normalization_forward::primitive_desc(lnorm_desc, dnnl_engine);
  // Primitive
  auto lnorm_prim = dnnl::layer_normalization_forward(lnorm_pd);

  // Define primitive arguments
  std::unordered_map<int, dnnl::memory> lnorm_args = {{DNNL_ARG_SRC, src_mem},
                                                      {DNNL_ARG_DST, src_mem}};
  // Get gamma
  auto gamma_mem = sp.GetMemory(node.Input(scale_pos));
  gamma_mem = sp.GetMemoryAndReshape(node.Input(scale_pos), gamma_mem.get_desc(), dnnl_engine);
  if (node.Input(scale_pos).Type() != dnnl::memory::data_type::f32) {
    //  casting to fp32 if input with other data type
    auto gamma_md = gamma_mem.get_desc();
    auto dims = gamma_md.dims();
    auto strides = gamma_md.data.format_desc.blocking.strides;
    dnnl::memory::dims gamma_strides_vec;
    for (size_t i = 0; i < dims.size(); i++) {
      gamma_strides_vec.push_back(strides[i]);
    }
    auto gamma_mem_f32 = CastAndTransformMemory(sp, gamma_mem, dnnl::memory::data_type::f32, gamma_strides_vec);
    lnorm_args.insert({DNNL_ARG_SCALE, gamma_mem_f32});
  } else {
    //  no casting if input with fp32
    lnorm_args.insert({DNNL_ARG_SCALE, gamma_mem});
  }

  // Get Beta and add shift if available
  if (shift_exists) {
    auto beta_mem = sp.GetMemory(node.Input(shift_pos));
    beta_mem = sp.GetMemoryAndReshape(node.Input(shift_pos), beta_mem.get_desc(), dnnl_engine);
    if (node.Input(shift_pos).Type() != dnnl::memory::data_type::f32) {
      //  casting to fp32 if input with other data type
      auto beta_md = beta_mem.get_desc();
      auto dims = beta_md.dims();
      auto strides = beta_md.data.format_desc.blocking.strides;
      dnnl::memory::dims beta_strides_vec;
      for (size_t i = 0; i < dims.size(); i++) {
        beta_strides_vec.push_back(strides[i]);
      }
      auto beta_mem_f32 = CastAndTransformMemory(sp, beta_mem, dnnl::memory::data_type::f32, beta_strides_vec);
      lnorm_args.insert({DNNL_ARG_SHIFT, beta_mem_f32});
    } else {
      //  no casting if input with fp32
      lnorm_args.insert({DNNL_ARG_SHIFT, beta_mem});
    }
  }

// Check outputs used for training
#if 0 //defined(ENABLE_TRAINING)
  // If Mean exists
  if (node.OutputCount() > 1) {
    if (node.Output(OUT_MEAN).Exists()) {
      auto mean_mem = dnnl::memory(lnorm_pd.mean_desc(), dnnl_engine);
      lnorm_args.insert({DNNL_ARG_MEAN, mean_mem});
      sp.SetMemory(node.Output(OUT_MEAN), mean_mem);
    }
    // If Variance exists
    if (node.Output(OUT_INV_STD_VAR).Exists()) {
      auto variance_mem = dnnl::memory(lnorm_pd.variance_desc(), dnnl_engine);
      lnorm_args.insert({DNNL_ARG_VARIANCE, variance_mem});
      sp.SetMemory(node.Output(OUT_INV_STD_VAR), variance_mem);
    }
  }
#endif  // ENABLE_TRAINING

  sp.AddPrimitive(lnorm_prim, lnorm_args);

  sp.SetMemory(node.Output(OUT_OUTPUT), src_mem, true);
}

dnnl::memory DnnlLayerNorm::BuildSLN(DnnlSubgraphPrimitive& sp, DnnlNode& node, dnnl::engine dnnl_engine) {
  // X += SKIP
  // Get input and skip info
  auto input_md = sp.GetMemory(node.Input(IN_INPUT)).get_desc();
  auto skip_md = sp.GetMemory(node.Input(IN_SKIP)).get_desc();
  auto skip_dims = skip_md.dims();

  // Create primitive input map
  std::unordered_map<int, dnnl::memory> skip_bias_args;

  // Create md for the add op, according to the spec the output type should be
  // the same as the input, so we can support inplace ops
  auto add_skip_dst_md = dnnl::memory::desc(skip_dims, node.Output(OUT_OUTPUT).Type(), dnnl::memory::format_tag::any);
  // Create desc for the op and primitive
  auto add_skip_d = dnnl::binary::desc(dnnl::algorithm::binary_add, input_md, skip_md, add_skip_dst_md);

  // Create primitive descriptor container
  dnnl::binary::primitive_desc add_skip_pd;
  // Add post op bias
  if (node.Input(IN_SLN_BIAS).Exists()) {
    // X += BIAS
    // Get bias md
    auto bias_md = sp.GetMemory(node.Input(IN_SLN_BIAS)).get_desc();
    auto bias_dims = bias_md.dims();
    // To follow the spec means our bias will always have less dimensions that our input}
    // so we add the extra dimensions, reshape it and let OneDNN broadcast the value
    while (bias_dims.size() < skip_dims.size()) {
      bias_dims.insert(bias_dims.begin(), 1);
    }
    bias_md = bias_md.reshape(bias_dims);

    dnnl::post_ops bias_add;
    dnnl::primitive_attr binary_attr;
    bias_add.append_binary(dnnl::algorithm::binary_add, bias_md);
    binary_attr.set_post_ops(bias_add);
    // Add post op to scale result
    add_skip_pd = dnnl::binary::primitive_desc(add_skip_d, binary_attr, dnnl_engine);

    // Get bias mem
    auto bias_mem = sp.GetMemoryAndReshape(node.Input(IN_SLN_BIAS), bias_md, dnnl_engine);
    // Add bias arg
    skip_bias_args.insert({DNNL_ARG_ATTR_MULTIPLE_POST_OP(0) | DNNL_ARG_SRC_1, bias_mem});

  } else {
    add_skip_pd = dnnl::binary::primitive_desc(add_skip_d, dnnl_engine);
  }

  // Move the memory to the target device
  auto src_mem = sp.GetMemoryAndReshape(node.Input(IN_INPUT), add_skip_pd.src0_desc(), dnnl_engine);
  auto skip_mem = sp.GetMemoryAndReshape(node.Input(IN_SKIP), add_skip_pd.src1_desc(), dnnl_engine);

  // Add args
  skip_bias_args.insert({DNNL_ARG_SRC_0, src_mem});
  skip_bias_args.insert({DNNL_ARG_SRC_1, skip_mem});
  skip_bias_args.insert({DNNL_ARG_DST, src_mem});

  // Create and add primitive
  auto add_skip_prim = dnnl::binary(add_skip_pd);
  sp.AddPrimitive(add_skip_prim, skip_bias_args);

  // Return src
  return src_mem;
}

void DnnlLayerNorm::ValidateDims(DnnlSubgraphPrimitive& sp, DnnlNode& node) {
  // Get input and evaluate
  auto input_dims = sp.GetMemory(node.Input(IN_INPUT)).get_desc().dims();
  auto input_dims_size = input_dims.size();

  // Check the inputs are supported by OneDNN, this is mandatory since sometimes
  // we can't check the input size in the node capability
  if ((input_dims_size > 5) || (input_dims_size < 2)) {
    ORT_THROW("Input tensor dimensionality is not supported by OneDNN, got ", input_dims_size);
  }

  // To make this function compliant with all possible layernorm flavors,
  // define gamma and shift input position, depending on the operation
  int gamma_pos, shift_pos;
  if (node.OpType() == "SkipLayerNormalization") {
    // For SkipLayerNorm the spec defines the input as a 3D tensor
    if (input_dims_size != 3) {
      // We support 2D arrays but the expected is 3D
      ORT_THROW("Input tensor is expected to have 3 dimensions, got ", input_dims_size);
    }

    // Get skip and evaluate
    auto skip_dims = sp.GetMemory(node.Input(IN_SKIP)).get_desc().dims();
    if (input_dims != skip_dims) {
      ORT_THROW("Input and skip dimmentions do not match");
    }

    // Check if bias was provided and evaluate
    if (node.Input(IN_SLN_BIAS).Exists()) {
      auto bias_dims = sp.GetMemory(node.Input(IN_SLN_BIAS)).get_desc().dims();
      if (bias_dims.size() != 1) {
        ORT_THROW("Bias is expected to have 1 dimension, got ", bias_dims.size());
      }
      if (bias_dims[0] != input_dims[2]) {
        ORT_THROW("Last dimension of bias and input does not match");
      }
    }

    // Define the input position when using SLN
    gamma_pos = IN_SLN_GAMMA;
    shift_pos = IN_BETA;

  // If the op is LayerNorm
  } else{
    // Define the input position when using LN
    gamma_pos = IN_LN_GAMMA;
    shift_pos = IN_LN_BIAS;
  }

  // Get gamma and evaluate
  auto gamma_dims = sp.GetMemory(node.Input(gamma_pos)).get_desc().dims();
  if (gamma_dims.size() != 1) {
    ORT_THROW("Gamma is expected to have 1 dimension, got ", gamma_dims.size());
  }
  if (gamma_dims[0] != input_dims[input_dims_size - 1]) {
    ORT_THROW("Last dimension of gamma and input does not match");
  }

  // Check if shift was provided and evaluate
  if (node.Input(shift_pos).Exists()) {
    auto beta_dims = sp.GetMemory(node.Input(shift_pos)).get_desc().dims();
    if (beta_dims.size() != 1) {
      ORT_THROW("Beta is expected to have 1 dimension, got ", beta_dims.size());
    }
    if (beta_dims[0] != input_dims[input_dims_size - 1]) {
      ORT_THROW("Last dimension of beta and input does not match");
    }
  }
}

float DnnlLayerNorm::GetEpsilon(DnnlNode& node) {
  auto attr = node.Attributes().find("epsilon");
  float epsilon = 1e-05f;  // Default value according to ONNX spec
  if (attr != node.Attributes().end() &&
      attr->second().type() == ::ONNX_NAMESPACE::AttributeProto_AttributeType::AttributeProto_AttributeType_FLOAT) {
    epsilon = attr->second().f();
  }
  return epsilon;
}

dnnl::memory DnnlLayerNorm::CastAndTransformMemory(DnnlSubgraphPrimitive& sp, dnnl::memory& src_mem, dnnl::memory::data_type dst_datatype, dnnl::memory::dims dst_strides) {
  dnnl::memory dst_mem;
  {
    auto eng = sp.GetEngine();

    // Make a new memory descriptor based on the source descriptor and given destination dataype and strides
    auto src_md = src_mem.get_desc();
    dnnl::memory::desc dst_md = dnnl::memory::desc(src_md.dims(), dst_datatype, dst_strides);
    dst_mem = dnnl::memory(dst_md, eng);

    // Reorder source memory to destination memory as per the given dataype and strides
    auto reorder_pd = dnnl::reorder::primitive_desc(eng, src_md, eng, dst_md);
    auto reorder = dnnl::reorder(reorder_pd);
    std::unordered_map<int, dnnl::memory> reorder_mem_map({{DNNL_ARG_FROM, src_mem}, {DNNL_ARG_TO, dst_mem}});
    sp.AddPrimitive(reorder, reorder_mem_map);
  }
  return dst_mem;
}

}  // namespace ort_dnnl
}  // namespace onnxruntime<commit_msg>[oneDNN ep] SLN performance improvement for bias (#13620)<commit_after>// Copyright(C) 2022 Intel Corporation
// Licensed under the MIT License

#include "dnnl_layernorm.h"
#include "dnnl_subgraph.h"
#include "dnnl_subgraph_primitive.h"

namespace onnxruntime {
namespace ort_dnnl {

DnnlLayerNorm::DnnlLayerNorm() {}

/*
Layer Normalization and Skip Layer Normalization implementation:
Layer Norm:
  Inputs:
    0) X - Input Tensor
    1) G - Gamma Tensor (Scaling factor in the LN formula)
    2) B - Bias Tensor (Shift value in the LN formula. Optional)
  Outputs:
    0) Y - Output Tensor
    1) M - Mean Tensor (Optional)
    2) I - Inverse std Tensor (Optional)

               +-----------+
(X) ---------->+           +----------> (Y)
               |           |
(G) ---------->+ LayerNorm +----------> (M)
               |           |
(B) ---------->+           +----------> (I)
               +-----------+

Skip Layer Norm:
  Inputs:
    0) X - Input Tensor
    1) S - Skip Tensor
    2) G - Gamma Tensor (Scaling factor in the LN formula)
    4) E - Beta Tensor (Shift value in the LN formula. Optional)
    4) B - Bias Tensor (Bias when adding X + S. Optional)
  Outputs:
    0) Y - Output Tensor
    1) M - Mean Tensor (Optional)
    2) I - Inverse std Tensor (Optional)

(X) ---------->+-----------+
               |    Add    |
(S) ---------->+-----------+
                     |                           +-----------+
                     |              (X + S + B)  |           |
                     +-----------+-------------->+           +----------> (Y)
                     |    Add    |               |           |
(B) ---------------->+-----------+   (G) ------->+ LayerNorm +----------> (M)
                                                 |           |
                                     (E) ------->+           +----------> (I)
                                                 |           |
                                                 +-----------+

Attributes (epsilon)
*/
void DnnlLayerNorm::CreatePrimitive(DnnlSubgraphPrimitive& sp, DnnlNode& node) {

  // Get engine
  auto dnnl_engine = sp.GetEngine();

  // Make sure every input's dimension follows the spec
  ValidateDims(sp, node);

  // Optional input flag
  bool shift_exists = false;

  // Input positions
  int shift_pos, scale_pos;

  // Get src desc
  auto src_md = sp.GetMemory(node.Input(IN_INPUT)).get_desc();

  // Init src mem
  dnnl::memory src_mem;

  // This contains the layer norm op and its parameters
  ln_components op_comps;
  if (node.OpType() == "SkipLayerNormalization") {

    // Check if shift is available
    shift_exists = node.Input(IN_BETA).Exists();

    // Fix positions for arguments
    shift_pos = IN_BETA;
    scale_pos = IN_SLN_GAMMA;

    // Move the src to GPU if needed
    src_mem = sp.GetMemoryAndReshape(node.Input(IN_INPUT), src_md, dnnl_engine);

    // Make dst desc, must be same as src
    auto dst_md = dnnl::memory::desc(src_md.dims(), node.Output(OUT_OUTPUT).Type(), dnnl::memory::format_tag::any);

    // Add src + skip
    {

      // get skip desc
      auto skip_md = sp.GetMemory(node.Input(IN_SKIP)).get_desc();
      // Move the skip to GPU if needed
      auto skip_mem = sp.GetMemoryAndReshape(node.Input(IN_SKIP), skip_md, dnnl_engine);

      // Create and add primitive
      auto add_skip_d = dnnl::binary::desc(dnnl::algorithm::binary_add, src_md, skip_md, dst_md);
      auto add_skip_pd = dnnl::binary::primitive_desc(add_skip_d, dnnl_engine);
      auto add_skip = dnnl::binary(add_skip_pd);
      std::unordered_map<int, dnnl::memory> add_skip_mem_map({{DNNL_ARG_SRC_0, src_mem}, {DNNL_ARG_SRC_1, skip_mem}, {DNNL_ARG_DST, src_mem}});
      sp.AddPrimitive(add_skip, add_skip_mem_map);

    }

    // Add src + skip + bias
    if (node.Input(IN_SLN_BIAS).Exists()) {

      // get bias desc
      auto bias_md = sp.GetMemory(node.Input(IN_SLN_BIAS)).get_desc();
      // Move the bias to GPU if needed
      auto bias_mem = sp.GetMemoryAndReshape(node.Input(IN_SLN_BIAS), bias_md, dnnl_engine);
      // Get bias dims
      auto bias_dims = bias_md.dims();
      // Get src dims
      auto src_dims = src_md.dims();

      // To follow the spec means our bias will always have less dimensions that our input
      // so we add the extra dimensions, reshape it and let OneDNN broadcast the value
      while (bias_dims.size() < src_dims.size()) {
        bias_dims.insert(bias_dims.begin(), 1);
      }
      bias_md = bias_md.reshape(bias_dims);

      // Create and add primitive
      auto add_bias_d = dnnl::binary::desc(dnnl::algorithm::binary_add, src_md, bias_md, dst_md);
      auto add_bias_pd = dnnl::binary::primitive_desc(add_bias_d, dnnl_engine);
      auto add_bias = dnnl::binary(add_bias_pd);
      std::unordered_map<int, dnnl::memory> add_bias_mem_map({{DNNL_ARG_SRC_0, src_mem}, {DNNL_ARG_SRC_1, bias_mem}, {DNNL_ARG_DST, src_mem}});
      sp.AddPrimitive(add_bias, add_bias_mem_map);

    }

  } else if (node.OpType() == "LayerNormalization") {

    // Check if shift is available
    shift_exists = node.Input(IN_LN_BIAS).Exists();

    // Fix positions for arguments
    shift_pos = IN_LN_BIAS;
    scale_pos = IN_LN_GAMMA;

    // Move the src to GPU if needed
    src_mem = sp.GetMemoryAndReshape(node.Input(IN_INPUT), src_md, dnnl_engine);

  } else {
    ORT_THROW("Unknown LayerNormalization flavor");
  }

  // X = LayerNornm(X)
  // Check if we are training and need the extra outputs for backprop
  dnnl::prop_kind prop_kind;
#if 0 //defined(ENABLE_TRAINING)
  prop_kind = dnnl::prop_kind::forward_training;
#else
  prop_kind = dnnl::prop_kind::forward_inference;
#endif  // ENABLE_TRAINING

  // If beta is available use shift, else only scale
  dnnl::normalization_flags op_flags = dnnl::normalization_flags::use_scale;
  if (shift_exists) {
    op_flags |= dnnl::normalization_flags::use_shift;
  }

  // Get epsilon to avoid zero division
  float epsilon = GetEpsilon(node);
  // Operation desciptor
  auto lnorm_desc = dnnl::layer_normalization_forward::desc(prop_kind, src_md, epsilon, op_flags);
  // Primitive desciptor
  auto lnorm_pd = dnnl::layer_normalization_forward::primitive_desc(lnorm_desc, dnnl_engine);
  // Primitive
  auto lnorm_prim = dnnl::layer_normalization_forward(lnorm_pd);

  // Define primitive arguments
  std::unordered_map<int, dnnl::memory> lnorm_args = {{DNNL_ARG_SRC, src_mem},
                                                      {DNNL_ARG_DST, src_mem}};
  // Get gamma
  auto gamma_mem = sp.GetMemory(node.Input(scale_pos));
  gamma_mem = sp.GetMemoryAndReshape(node.Input(scale_pos), gamma_mem.get_desc(), dnnl_engine);
  if (node.Input(scale_pos).Type() != dnnl::memory::data_type::f32) {
    //  casting to fp32 if input with other data type
    auto gamma_md = gamma_mem.get_desc();
    auto dims = gamma_md.dims();
    auto strides = gamma_md.data.format_desc.blocking.strides;
    dnnl::memory::dims gamma_strides_vec;
    for (size_t i = 0; i < dims.size(); i++) {
      gamma_strides_vec.push_back(strides[i]);
    }
    auto gamma_mem_f32 = CastAndTransformMemory(sp, gamma_mem, dnnl::memory::data_type::f32, gamma_strides_vec);
    lnorm_args.insert({DNNL_ARG_SCALE, gamma_mem_f32});
  } else {
    //  no casting if input with fp32
    lnorm_args.insert({DNNL_ARG_SCALE, gamma_mem});
  }

  // Get Beta and add shift if available
  if (shift_exists) {
    auto beta_mem = sp.GetMemory(node.Input(shift_pos));
    beta_mem = sp.GetMemoryAndReshape(node.Input(shift_pos), beta_mem.get_desc(), dnnl_engine);
    if (node.Input(shift_pos).Type() != dnnl::memory::data_type::f32) {
      //  casting to fp32 if input with other data type
      auto beta_md = beta_mem.get_desc();
      auto dims = beta_md.dims();
      auto strides = beta_md.data.format_desc.blocking.strides;
      dnnl::memory::dims beta_strides_vec;
      for (size_t i = 0; i < dims.size(); i++) {
        beta_strides_vec.push_back(strides[i]);
      }
      auto beta_mem_f32 = CastAndTransformMemory(sp, beta_mem, dnnl::memory::data_type::f32, beta_strides_vec);
      lnorm_args.insert({DNNL_ARG_SHIFT, beta_mem_f32});
    } else {
      //  no casting if input with fp32
      lnorm_args.insert({DNNL_ARG_SHIFT, beta_mem});
    }
  }

// Check outputs used for training
#if 0 //defined(ENABLE_TRAINING)
  // If Mean exists
  if (node.OutputCount() > 1) {
    if (node.Output(OUT_MEAN).Exists()) {
      auto mean_mem = dnnl::memory(lnorm_pd.mean_desc(), dnnl_engine);
      lnorm_args.insert({DNNL_ARG_MEAN, mean_mem});
      sp.SetMemory(node.Output(OUT_MEAN), mean_mem);
    }
    // If Variance exists
    if (node.Output(OUT_INV_STD_VAR).Exists()) {
      auto variance_mem = dnnl::memory(lnorm_pd.variance_desc(), dnnl_engine);
      lnorm_args.insert({DNNL_ARG_VARIANCE, variance_mem});
      sp.SetMemory(node.Output(OUT_INV_STD_VAR), variance_mem);
    }
  }
#endif  // ENABLE_TRAINING

  sp.AddPrimitive(lnorm_prim, lnorm_args);

  sp.SetMemory(node.Output(OUT_OUTPUT), src_mem, true);
}

void DnnlLayerNorm::ValidateDims(DnnlSubgraphPrimitive& sp, DnnlNode& node) {
  // Get input and evaluate
  auto input_dims = sp.GetMemory(node.Input(IN_INPUT)).get_desc().dims();
  auto input_dims_size = input_dims.size();

  // Check the inputs are supported by OneDNN, this is mandatory since sometimes
  // we can't check the input size in the node capability
  if ((input_dims_size > 5) || (input_dims_size < 2)) {
    ORT_THROW("Input tensor dimensionality is not supported by OneDNN, got ", input_dims_size);
  }

  // To make this function compliant with all possible layernorm flavors,
  // define gamma and shift input position, depending on the operation
  int gamma_pos, shift_pos;
  if (node.OpType() == "SkipLayerNormalization") {
    // For SkipLayerNorm the spec defines the input as a 3D tensor
    if (input_dims_size != 3) {
      // We support 2D arrays but the expected is 3D
      ORT_THROW("Input tensor is expected to have 3 dimensions, got ", input_dims_size);
    }

    // Get skip and evaluate
    auto skip_dims = sp.GetMemory(node.Input(IN_SKIP)).get_desc().dims();
    if (input_dims != skip_dims) {
      ORT_THROW("Input and skip dimmentions do not match");
    }

    // Check if bias was provided and evaluate
    if (node.Input(IN_SLN_BIAS).Exists()) {
      auto bias_dims = sp.GetMemory(node.Input(IN_SLN_BIAS)).get_desc().dims();
      if (bias_dims.size() != 1) {
        ORT_THROW("Bias is expected to have 1 dimension, got ", bias_dims.size());
      }
      if (bias_dims[0] != input_dims[2]) {
        ORT_THROW("Last dimension of bias and input does not match");
      }
    }

    // Define the input position when using SLN
    gamma_pos = IN_SLN_GAMMA;
    shift_pos = IN_BETA;

  // If the op is LayerNorm
  } else{
    // Define the input position when using LN
    gamma_pos = IN_LN_GAMMA;
    shift_pos = IN_LN_BIAS;
  }

  // Get gamma and evaluate
  auto gamma_dims = sp.GetMemory(node.Input(gamma_pos)).get_desc().dims();
  if (gamma_dims.size() != 1) {
    ORT_THROW("Gamma is expected to have 1 dimension, got ", gamma_dims.size());
  }
  if (gamma_dims[0] != input_dims[input_dims_size - 1]) {
    ORT_THROW("Last dimension of gamma and input does not match");
  }

  // Check if shift was provided and evaluate
  if (node.Input(shift_pos).Exists()) {
    auto beta_dims = sp.GetMemory(node.Input(shift_pos)).get_desc().dims();
    if (beta_dims.size() != 1) {
      ORT_THROW("Beta is expected to have 1 dimension, got ", beta_dims.size());
    }
    if (beta_dims[0] != input_dims[input_dims_size - 1]) {
      ORT_THROW("Last dimension of beta and input does not match");
    }
  }
}

float DnnlLayerNorm::GetEpsilon(DnnlNode& node) {
  auto attr = node.Attributes().find("epsilon");
  float epsilon = 1e-05f;  // Default value according to ONNX spec
  if (attr != node.Attributes().end() &&
      attr->second().type() == ::ONNX_NAMESPACE::AttributeProto_AttributeType::AttributeProto_AttributeType_FLOAT) {
    epsilon = attr->second().f();
  }
  return epsilon;
}

dnnl::memory DnnlLayerNorm::CastAndTransformMemory(DnnlSubgraphPrimitive& sp, dnnl::memory& src_mem, dnnl::memory::data_type dst_datatype, dnnl::memory::dims dst_strides) {
  dnnl::memory dst_mem;
  {
    auto eng = sp.GetEngine();

    // Make a new memory descriptor based on the source descriptor and given destination dataype and strides
    auto src_md = src_mem.get_desc();
    dnnl::memory::desc dst_md = dnnl::memory::desc(src_md.dims(), dst_datatype, dst_strides);
    dst_mem = dnnl::memory(dst_md, eng);

    // Reorder source memory to destination memory as per the given dataype and strides
    auto reorder_pd = dnnl::reorder::primitive_desc(eng, src_md, eng, dst_md);
    auto reorder = dnnl::reorder(reorder_pd);
    std::unordered_map<int, dnnl::memory> reorder_mem_map({{DNNL_ARG_FROM, src_mem}, {DNNL_ARG_TO, dst_mem}});
    sp.AddPrimitive(reorder, reorder_mem_map);
  }
  return dst_mem;
}

}  // namespace ort_dnnl
}  // namespace onnxruntime<|endoftext|>


<commit_before>/*
Copyright (c) 2010, Dan Bethell, Johannes Saam.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

    * Neither the name of RenderConnect nor the names of its contributors may be
    used to endorse or promote products derived from this software without
    specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <iostream>
#include <exception>
#include <cstring>

#include "Client.h"
#include "Data.h"

#include <ai.h>
#include <ai_critsec.h>
#include <ai_drivers.h>
#include <ai_filters.h>
#include <ai_msg.h>
#include <ai_render.h>
#include <ai_universe.h>

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
#include <boost/format.hpp>

#include <stdio.h>
#include <iostream>
#include <deque>

using namespace std;
using boost::asio::ip::tcp;

AI_DRIVER_NODE_EXPORT_METHODS(NukeDriverMtd);

struct ShaderData
{
   //boost::thread  thread;
   //void* thread;
   renderconnect::Client *client;
};

node_parameters
{
   AiParameterSTR("host", "127.0.0.1");
   AiParameterINT("port", 9201);
   AiMetaDataSetStr(mds, NULL, "maya.translator", "nuke");
   AiMetaDataSetStr(mds, NULL, "maya.attr_prefix", "");
}

node_initialize
{
   AiDriverInitialize(node, true, AiMalloc(sizeof(ShaderData)));
}

node_update
{
}

driver_supports_pixel_type
{
   return true;
}

driver_extension
{
   return NULL;
}

driver_open
{

   ShaderData *data = (ShaderData*)AiDriverGetLocalData(node);

   const char* host = AiNodeGetStr(node, "host");
   int  port = AiNodeGetInt(node, "port");
   int width = display_window.maxx - display_window.minx +1;
   int height = display_window.maxy - display_window.miny +1;
   // now we can connect to the server and start rendering
   try
   {
       // create a new renderConnect object
       data->client = new renderconnect::Client( host, port );

       // make image header & send to server
       renderconnect::Data header( 0, 0, width, height, 4 );
       data->client->openImage( header );
   }
   catch (const std::exception &e)
   {
       AiMsgError("RenderConnect display driver", "%s", e.what());
   }

//   data->nchannels = 0;
//   unsigned int i = 0;
//   while (AiOutputIteratorGetNext(iterator, &aov_name, &pixel_type, NULL))
//   {
//      aov_list.push_back(aov_name);
//      if (i > 0)
//         aov_names += ",";
//      aov_names += std::string("\"") + aov_name + "\"";
//      switch(pixel_type)
//      {
//         case AI_TYPE_RGB:
//            data->nchannels = MAX(data->nchannels, 3);
//            break;
//         case AI_TYPE_RGBA:
//            data->nchannels = MAX(data->nchannels, 4);
//            break;
//         default:
//            break;
//      }
//      i++;
//   }

}

driver_prepare_bucket
{
   AiMsgDebug("[renderConnect] prepare bucket (%d, %d)", bucket_xo, bucket_yo);

   //
}

driver_write_bucket
{
   ShaderData *data = (ShaderData*)AiDriverGetLocalData(node);

   int         pixel_type;
   const void* bucket_data;
   const char* aov_name;

   while (AiOutputIteratorGetNext(iterator, &aov_name, &pixel_type, &bucket_data))
   {
       const float *ptr = reinterpret_cast<const float*> (bucket_data);

       // create our data object
       renderconnect::Data packet(bucket_xo, bucket_yo,
                                  bucket_size_x, bucket_size_y,
                                  4, ptr);

       // send it to the server
       data->client->sendPixels(packet);
   }
}

driver_close
{
   AiMsgInfo("[renderConnect] driver close");

   ShaderData *data = (ShaderData*)AiDriverGetLocalData(node);
   data->client->closeImage();
}

node_finish
{
   AiMsgInfo("[renderConnect] driver finish");
   // release the driver

   ShaderData *data = (ShaderData*)AiDriverGetLocalData(node);
   delete data->client;

   AiFree(data);
   AiDriverDestroy(node);
}

node_loader
{
   sprintf(node->version, AI_VERSION);

   switch (i)
   {
      case 0:
         node->methods      = (AtNodeMethods*) NukeDriverMtd;
         node->output_type  = AI_TYPE_RGBA;
         node->name         = "driver_nuke";
         node->node_type    = AI_NODE_DRIVER;
         break;
      default:
      return false;
   }
   return true;
}

<commit_msg>Update d_arnoldConnect.cpp<commit_after>/*
Copyright (c) 2010, Dan Bethell, Johannes Saam.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

    * Neither the name of RenderConnect nor the names of its contributors may be
    used to endorse or promote products derived from this software without
    specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <iostream>
#include <exception>
#include <cstring>

#include "Client.h"
#include "Data.h"

#include <ai.h>
#include <ai_critsec.h>
#include <ai_drivers.h>
#include <ai_filters.h>
#include <ai_msg.h>
#include <ai_render.h>
#include <ai_universe.h>

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
#include <boost/format.hpp>

#include <stdio.h>
#include <iostream>
#include <deque>

using namespace std;
using boost::asio::ip::tcp;

AI_DRIVER_NODE_EXPORT_METHODS(NukeDriverMtd);

struct ShaderData
{
   //boost::thread  thread;
   //void* thread;
   renderconnect::Client *client;
};

node_parameters
{
   AiParameterSTR("host", "127.0.0.1");
   AiParameterINT("port", 9201);
   AiMetaDataSetStr(mds, NULL, "maya.translator", "nuke");
   AiMetaDataSetStr(mds, NULL, "maya.attr_prefix", "");
}

node_initialize
{
   AiDriverInitialize(node, true, AiMalloc(sizeof(ShaderData)));
}

node_update
{
}

driver_supports_pixel_type
{
   return true;
}

driver_extension
{
   return NULL;
}

driver_open
{

   ShaderData *data = (ShaderData*)AiDriverGetLocalData(node);

   const char* host = AiNodeGetStr(node, "host");
   int  port = AiNodeGetInt(node, "port");
   int width = display_window.maxx - display_window.minx +1;
   int height = display_window.maxy - display_window.miny +1;
   // now we can connect to the server and start rendering
   try
   {
       // create a new renderConnect object
       data->client = new renderconnect::Client( host, port );

       // make image header & send to server
       renderconnect::Data header( 0, 0, width, height, 4 );
       data->client->openImage( header );
   }
   catch (const std::exception &e)
   {
       AiMsgError("RenderConnect display driver", "%s", e.what());
   }

//   data->nchannels = 0;
//   unsigned int i = 0;
//   while (AiOutputIteratorGetNext(iterator, &aov_name, &pixel_type, NULL))
//   {
//      aov_list.push_back(aov_name);
//      if (i > 0)
//         aov_names += ",";
//      aov_names += std::string("\"") + aov_name + "\"";
//      switch(pixel_type)
//      {
//         case AI_TYPE_RGB:
//            data->nchannels = MAX(data->nchannels, 3);
//            break;
//         case AI_TYPE_RGBA:
//            data->nchannels = MAX(data->nchannels, 4);
//            break;
//         default:
//            break;
//      }
//      i++;
//   }

}

driver_needs_bucket
{
   return true;
}

driver_prepare_bucket
{
   AiMsgDebug("[renderConnect] prepare bucket (%d, %d)", bucket_xo, bucket_yo);
}

driver_process_bucket
{

}

driver_write_bucket
{
   ShaderData *data = (ShaderData*)AiDriverGetLocalData(node);

   int         pixel_type;
   const void* bucket_data;
   const char* aov_name;

   while (AiOutputIteratorGetNext(iterator, &aov_name, &pixel_type, &bucket_data))
   {
       const float *ptr = reinterpret_cast<const float*> (bucket_data);

       // create our data object
       renderconnect::Data packet(bucket_xo, bucket_yo,
                                  bucket_size_x, bucket_size_y,
                                  4, ptr);

       // send it to the server
       data->client->sendPixels(packet);
   }
}

driver_close
{
   AiMsgInfo("[renderConnect] driver close");

   ShaderData *data = (ShaderData*)AiDriverGetLocalData(node);
   data->client->closeImage();
}

node_finish
{
   AiMsgInfo("[renderConnect] driver finish");
   // release the driver

   ShaderData *data = (ShaderData*)AiDriverGetLocalData(node);
   delete data->client;

   AiFree(data);
   AiDriverDestroy(node);
}

node_loader
{
   sprintf(node->version, AI_VERSION);

   switch (i)
   {
      case 0:
         node->methods      = (AtNodeMethods*) NukeDriverMtd;
         node->output_type  = AI_TYPE_RGBA;
         node->name         = "driver_nuke";
         node->node_type    = AI_NODE_DRIVER;
         break;
      default:
      return false;
   }
   return true;
}

<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999, 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
// Class header file...
#include "XalanOutputStream.hpp"

#include <util/TransService.hpp>
#include <util/XMLException.hpp>

#include "XalanTranscodingServices.hpp"

XalanOutputStream::XalanOutputStream(
			BufferType::size_type			theBufferSize,
			TranscodeVectorType::size_type	theTranscoderBlockSize) :
	m_transcoderBlockSize(theTranscoderBlockSize),
	m_transcoder(0),
	m_bufferSize(theBufferSize),
	m_buffer(),
	m_encoding(),
	m_writeAsUTF16(false),
	m_transcodingBuffer()
{
	m_buffer.reserve(theBufferSize + 1);
}

XalanOutputStream::~XalanOutputStream()
{
	XalanTranscodingServices::destroyTranscoder(m_transcoder);
}

void
XalanOutputStream::flush()
{
	flushBuffer();

	doFlush();
}

void
XalanOutputStream::write(char	theChar)
{
	write(&theChar, 1);
}

void
XalanOutputStream::write(XalanDOMChar	theChar)
{
	write(&theChar, 1);
}

void
XalanOutputStream::write(
			const XalanDOMChar*		theBuffer,
			unsigned long			theBufferLength)
{
	assert(theBuffer != 0);

	if (theBufferLength + m_buffer.size() > m_bufferSize)
	{
		flushBuffer();
	}

	if (theBufferLength > m_bufferSize)
	{
		doWrite(theBuffer, theBufferLength);
	}
	else
	{
		m_buffer.insert(m_buffer.end(),
						theBuffer,
						theBuffer + theBufferLength);
	}
}

void
XalanOutputStream::write(const XalanDOMChar*	theBuffer)
{
	if (theBuffer != 0)
	{
		write(theBuffer, length(theBuffer));
	}
}

void
XalanOutputStream::write(const char*	theBuffer)
{
	assert(theBuffer != 0);

	flushBuffer();

	writeData(theBuffer,
		      strlen(theBuffer));
}

void
XalanOutputStream::write(
			const char*		theBuffer,
			unsigned long	theBufferLength)
{
	assert(theBuffer != 0);

	flushBuffer();

	writeData(theBuffer,
			  theBufferLength);
}

void
XalanOutputStream::transcode(
			const XalanDOMChar*		theBuffer,
			TranscodeVectorType&	theDestination)
{
	// This is a special version that will short-cut when
	// transocding to the local code page.  On platforms
	// where XalanDOMChar == wchar_t, it saves copying
	// to a temporary buffer for the purposes of null-
	// terminating the string.
	if (m_transcoder == 0)
	{
		if (TranscodeToLocalCodePage(
				theBuffer,
				theDestination) == false)
		{
			throw TranscodingException();
		}
	}
	else
	{
		transcode(theBuffer, length(theBuffer), theDestination);
	}
}

void
XalanOutputStream::transcode(
			const XalanDOMChar*		theBuffer,
			unsigned long			theBufferLength,
			TranscodeVectorType&	theDestination)
{
	if (m_transcoder == 0)
	{
		if (TranscodeToLocalCodePage(
				theBuffer,
				theBufferLength,
				theDestination) == false)
		{
			throw TranscodingException();
		}
	}
	else
	{
		bool					fDone = false;

		// Keep track of the total bytes we've added to the
		// destination vector, and the total bytes we've
		// eaten from theBuffer.
		unsigned int			theTotalBytesFilled = 0;
		unsigned int			theTotalBytesEaten = 0;

		// Keep track of the current position in the input buffer,
		// and amount remaining in the buffer, since we may not be
		// able to transcode it all at once.
		const XalanDOMChar*		theBufferPosition = theBuffer;
		unsigned int			theRemainingBufferLength = theBufferLength;

		// Keep track of the destination size, and the target size, which is
		// the size of the destination that has not yet been filled with
		// transcoded characters.  Double the buffer size, in case we're
		// transcoding to a 16-bit encoding.
		// $$$ ToDo: We need to know the size of an encoding, so we can
		// do the right thing with the destination size.
		unsigned int			theDestinationSize = theBufferLength * 2;
		unsigned int			theTargetSize = theDestinationSize;

		do
		{
			// Resize the buffer...
			theDestination.resize(theDestinationSize + 1);

			unsigned int						theSourceBytesEaten = 0;
			unsigned int						theTargetBytesEaten = 0;

			XalanTranscodingServices::eCode		theResult =
				m_transcoder->transcode(
						theBufferPosition,
						theRemainingBufferLength,
#if defined(XALAN_OLD_STYLE_CASTS)
						(XMLByte*)&theDestination[0] + theTotalBytesFilled,
#else
						reinterpret_cast<XMLByte*>(&theDestination[0]) + theTotalBytesFilled,
#endif
						theTargetSize,
						theSourceBytesEaten,
						theTargetBytesEaten);

			if(theResult != XalanTranscodingServices::OK)
			{
				throw TranscodingException();
			}

			theTotalBytesFilled += theTargetBytesEaten;
			theTotalBytesEaten += theSourceBytesEaten;

			if (theTotalBytesEaten == theBufferLength)
			{
				fDone = true;
			}
			else
			{
				assert(theTotalBytesEaten < theBufferLength);

				// Update everything...
				theBufferPosition += theSourceBytesEaten;
				theRemainingBufferLength -= theSourceBytesEaten;

				// The new target size will always be the
				// current destination size, since we
				// grow by a factor of 2.  This will
				// need to change if the factor is
				// every changed.
				theTargetSize = theDestinationSize;

				// Grow the destination by a factor of
				// two 2.  See the previous comment if
				// you want to change this.
				theDestinationSize = theDestinationSize * 2;
			}
		} while(fDone == false);

		// Resize things, if there are any extra bytes...
		if (theDestination.size() != theTotalBytesFilled)
		{
			theDestination.resize(theTotalBytesFilled);
		}
	}
}

const XalanDOMString&
XalanOutputStream::getOutputEncoding() const
{
	return m_encoding;
}

void
XalanOutputStream::setOutputEncoding(const XalanDOMString&	theEncoding)
{
	// Flush, just in case.  This should probably be an error...
	flushBuffer();

	XalanTranscodingServices::destroyTranscoder(m_transcoder);

	XalanTranscodingServices::eCode		theCode = XalanTranscodingServices::OK;

	// This turns on an optimization that we can only do if
	// XalanDOMChar == sizeof(ushort).  See doWrite().
#if !defined(XALAN_XALANDOMCHAR_USHORT_MISMATCH)
	if (XalanTranscodingServices::encodingIsUTF16(theEncoding) == true)
	{
		m_writeAsUTF16 = true;
	}
	else
#endif
	{
		m_transcoder = XalanTranscodingServices::makeNewTranscoder(
					theEncoding,
					theCode,
					m_transcoderBlockSize);

		if (theCode == XalanTranscodingServices::UnsupportedEncoding)
		{
			throw UnsupportedEncodingException(theEncoding);
		}
		else if (theCode != XalanTranscodingServices::OK)
		{
			throw TranscoderInternalFailureException(theEncoding);
		}

		assert(m_transcoder != 0);
	}

	m_encoding = theEncoding;

	typedef XalanTranscodingServices::XalanXMLByteVectorType	XalanXMLByteVectorType;

	const XalanXMLByteVectorType&	theProlog =
		XalanTranscodingServices::getStreamProlog(theEncoding);

	const XalanXMLByteVectorType::size_type		theSize = theProlog.size();

	if (theSize > 0)
	{
#if defined(XALAN_OLD_STYLE_CASTS)
		write((const char*)theProlog[0], theProlog.size());
#else
		write(reinterpret_cast<const char*>(&theProlog[0]), theProlog.size());
#endif
	}
}

void
XalanOutputStream::flushBuffer()
{
	if (m_buffer.size() > 0)
	{
		m_buffer.push_back(0);

		doWrite(&*m_buffer.begin());

		m_buffer.clear();
	}
}

void
XalanOutputStream::doWrite(const XalanDOMChar*	theBuffer)
{
	assert(theBuffer != 0);

	try
	{
		if (m_writeAsUTF16 == true)
		{
			assert(sizeof(XalanDOMChar) == sizeof(char) * 2);

			// This is a hack to write UTF-16 through as if it
			// were just chars.  Saves lots of time "transcoding."
#if defined(XALAN_OLD_STYLE_CASTS)
			writeData((const char*)theBuffer, length(theBuffer) * 2);
#else
			writeData(reinterpret_cast<const char*>(theBuffer), length(theBuffer) * 2);
#endif
		}
		else
		{
			transcode(theBuffer, m_transcodingBuffer);

			assert(&m_transcodingBuffer[0] != 0);

			writeData(&m_transcodingBuffer[0],
					  m_transcodingBuffer.size());
		}
	}
	catch(const XalanOutputStreamException&)
	{
		// Have to catch this error and flush any output remaining...
		m_buffer.clear();

		throw;
	}
}

void
XalanOutputStream::doWrite(
			const XalanDOMChar*		theBuffer,
			unsigned long			theBufferLength)
{
	// $$$ ToDo: Revisit this!!!
	BufferType	theLocalBuffer(theBuffer, theBuffer + theBufferLength);

	theLocalBuffer.push_back(0);

	doWrite(&theLocalBuffer[0]);
}

void
XalanOutputStream::setBufferSize(BufferType::size_type		theBufferSize)
{
	flushBuffer();

	m_bufferSize = theBufferSize;

	if (m_buffer.size() < m_bufferSize)
	{
		// Enlarge the buffer...
		m_buffer.reserve(theBufferSize + 1);
	}
	else if (m_buffer.size() > m_bufferSize)
	{
		// Shrink the buffer.

		// Create a temp buffer and make it
		// the correct size.
		BufferType	temp;

		temp.reserve(theBufferSize + 1);

		// Swap temp with m_buffer so that
		// m_buffer is now the correct size.
		temp.swap(m_buffer);
	}
}

XalanOutputStream::XalanOutputStreamException::XalanOutputStreamException(
			const XalanDOMString&	theMessage,
			const XalanDOMString&	theType) :
	XSLException(theMessage, theType)
{
}

XalanOutputStream::XalanOutputStreamException::~XalanOutputStreamException()
{
}

XalanOutputStream::UnknownEncodingException::UnknownEncodingException() :
	XalanOutputStreamException(
			TranscodeFromLocalCodePage("Unknown error occurred while transcoding!"),
			TranscodeFromLocalCodePage("UnknownEncodingException"))
{
}

XalanOutputStream::UnknownEncodingException::~UnknownEncodingException()
{
}

XalanOutputStream::UnsupportedEncodingException::UnsupportedEncodingException(const XalanDOMString&	theEncoding) :
	XalanOutputStreamException(
			TranscodeFromLocalCodePage("Unsupported encoding: ") + theEncoding,
			TranscodeFromLocalCodePage("UnsupportedEncodingException")),
	m_encoding(theEncoding)
{
}

XalanOutputStream::UnsupportedEncodingException::~UnsupportedEncodingException()
{
}

XalanOutputStream::TranscoderInternalFailureException::TranscoderInternalFailureException(const XalanDOMString&	theEncoding) :
	XalanOutputStreamException(
			TranscodeFromLocalCodePage("Unknown error occurred while transcoding to ") +
					theEncoding +
					TranscodeFromLocalCodePage("!"),
			TranscodeFromLocalCodePage("TranscoderInternalFailureException")),
	m_encoding(theEncoding)
{
}

XalanOutputStream::TranscoderInternalFailureException::~TranscoderInternalFailureException()
{
}

XalanOutputStream::TranscodingException::TranscodingException() :
	XalanOutputStreamException(
			TranscodeFromLocalCodePage("An error occurred while transcoding!"),
			TranscodeFromLocalCodePage("TranscodingException"))
{
}

XalanOutputStream::TranscodingException::~TranscodingException()
{
}
<commit_msg>Fixed bug in call to write() with XALAN_OLD_STYLE_CASTS.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999, 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
// Class header file...
#include "XalanOutputStream.hpp"

#include <util/TransService.hpp>
#include <util/XMLException.hpp>

#include "XalanTranscodingServices.hpp"

XalanOutputStream::XalanOutputStream(
			BufferType::size_type			theBufferSize,
			TranscodeVectorType::size_type	theTranscoderBlockSize) :
	m_transcoderBlockSize(theTranscoderBlockSize),
	m_transcoder(0),
	m_bufferSize(theBufferSize),
	m_buffer(),
	m_encoding(),
	m_writeAsUTF16(false),
	m_transcodingBuffer()
{
	m_buffer.reserve(theBufferSize + 1);
}

XalanOutputStream::~XalanOutputStream()
{
	XalanTranscodingServices::destroyTranscoder(m_transcoder);
}

void
XalanOutputStream::flush()
{
	flushBuffer();

	doFlush();
}

void
XalanOutputStream::write(char	theChar)
{
	write(&theChar, 1);
}

void
XalanOutputStream::write(XalanDOMChar	theChar)
{
	write(&theChar, 1);
}

void
XalanOutputStream::write(
			const XalanDOMChar*		theBuffer,
			unsigned long			theBufferLength)
{
	assert(theBuffer != 0);

	if (theBufferLength + m_buffer.size() > m_bufferSize)
	{
		flushBuffer();
	}

	if (theBufferLength > m_bufferSize)
	{
		doWrite(theBuffer, theBufferLength);
	}
	else
	{
		m_buffer.insert(m_buffer.end(),
						theBuffer,
						theBuffer + theBufferLength);
	}
}

void
XalanOutputStream::write(const XalanDOMChar*	theBuffer)
{
	if (theBuffer != 0)
	{
		write(theBuffer, length(theBuffer));
	}
}

void
XalanOutputStream::write(const char*	theBuffer)
{
	assert(theBuffer != 0);

	flushBuffer();

	writeData(theBuffer,
		      strlen(theBuffer));
}

void
XalanOutputStream::write(
			const char*		theBuffer,
			unsigned long	theBufferLength)
{
	assert(theBuffer != 0);

	flushBuffer();

	writeData(theBuffer,
			  theBufferLength);
}

void
XalanOutputStream::transcode(
			const XalanDOMChar*		theBuffer,
			TranscodeVectorType&	theDestination)
{
	// This is a special version that will short-cut when
	// transocding to the local code page.  On platforms
	// where XalanDOMChar == wchar_t, it saves copying
	// to a temporary buffer for the purposes of null-
	// terminating the string.
	if (m_transcoder == 0)
	{
		if (TranscodeToLocalCodePage(
				theBuffer,
				theDestination) == false)
		{
			throw TranscodingException();
		}
	}
	else
	{
		transcode(theBuffer, length(theBuffer), theDestination);
	}
}

void
XalanOutputStream::transcode(
			const XalanDOMChar*		theBuffer,
			unsigned long			theBufferLength,
			TranscodeVectorType&	theDestination)
{
	if (m_transcoder == 0)
	{
		if (TranscodeToLocalCodePage(
				theBuffer,
				theBufferLength,
				theDestination) == false)
		{
			throw TranscodingException();
		}
	}
	else
	{
		bool					fDone = false;

		// Keep track of the total bytes we've added to the
		// destination vector, and the total bytes we've
		// eaten from theBuffer.
		unsigned int			theTotalBytesFilled = 0;
		unsigned int			theTotalBytesEaten = 0;

		// Keep track of the current position in the input buffer,
		// and amount remaining in the buffer, since we may not be
		// able to transcode it all at once.
		const XalanDOMChar*		theBufferPosition = theBuffer;
		unsigned int			theRemainingBufferLength = theBufferLength;

		// Keep track of the destination size, and the target size, which is
		// the size of the destination that has not yet been filled with
		// transcoded characters.  Double the buffer size, in case we're
		// transcoding to a 16-bit encoding.
		// $$$ ToDo: We need to know the size of an encoding, so we can
		// do the right thing with the destination size.
		unsigned int			theDestinationSize = theBufferLength * 2;
		unsigned int			theTargetSize = theDestinationSize;

		do
		{
			// Resize the buffer...
			theDestination.resize(theDestinationSize + 1);

			unsigned int						theSourceBytesEaten = 0;
			unsigned int						theTargetBytesEaten = 0;

			XalanTranscodingServices::eCode		theResult =
				m_transcoder->transcode(
						theBufferPosition,
						theRemainingBufferLength,
#if defined(XALAN_OLD_STYLE_CASTS)
						(XMLByte*)&theDestination[0] + theTotalBytesFilled,
#else
						reinterpret_cast<XMLByte*>(&theDestination[0]) + theTotalBytesFilled,
#endif
						theTargetSize,
						theSourceBytesEaten,
						theTargetBytesEaten);

			if(theResult != XalanTranscodingServices::OK)
			{
				throw TranscodingException();
			}

			theTotalBytesFilled += theTargetBytesEaten;
			theTotalBytesEaten += theSourceBytesEaten;

			if (theTotalBytesEaten == theBufferLength)
			{
				fDone = true;
			}
			else
			{
				assert(theTotalBytesEaten < theBufferLength);

				// Update everything...
				theBufferPosition += theSourceBytesEaten;
				theRemainingBufferLength -= theSourceBytesEaten;

				// The new target size will always be the
				// current destination size, since we
				// grow by a factor of 2.  This will
				// need to change if the factor is
				// every changed.
				theTargetSize = theDestinationSize;

				// Grow the destination by a factor of
				// two 2.  See the previous comment if
				// you want to change this.
				theDestinationSize = theDestinationSize * 2;
			}
		} while(fDone == false);

		// Resize things, if there are any extra bytes...
		if (theDestination.size() != theTotalBytesFilled)
		{
			theDestination.resize(theTotalBytesFilled);
		}
	}
}

const XalanDOMString&
XalanOutputStream::getOutputEncoding() const
{
	return m_encoding;
}

void
XalanOutputStream::setOutputEncoding(const XalanDOMString&	theEncoding)
{
	// Flush, just in case.  This should probably be an error...
	flushBuffer();

	XalanTranscodingServices::destroyTranscoder(m_transcoder);

	XalanTranscodingServices::eCode		theCode = XalanTranscodingServices::OK;

	// This turns on an optimization that we can only do if
	// XalanDOMChar == sizeof(ushort).  See doWrite().
#if !defined(XALAN_XALANDOMCHAR_USHORT_MISMATCH)
	if (XalanTranscodingServices::encodingIsUTF16(theEncoding) == true)
	{
		m_writeAsUTF16 = true;
	}
	else
#endif
	{
		m_transcoder = XalanTranscodingServices::makeNewTranscoder(
					theEncoding,
					theCode,
					m_transcoderBlockSize);

		if (theCode == XalanTranscodingServices::UnsupportedEncoding)
		{
			throw UnsupportedEncodingException(theEncoding);
		}
		else if (theCode != XalanTranscodingServices::OK)
		{
			throw TranscoderInternalFailureException(theEncoding);
		}

		assert(m_transcoder != 0);
	}

	m_encoding = theEncoding;

	typedef XalanTranscodingServices::XalanXMLByteVectorType	XalanXMLByteVectorType;

	const XalanXMLByteVectorType&	theProlog =
		XalanTranscodingServices::getStreamProlog(theEncoding);

	const XalanXMLByteVectorType::size_type		theSize = theProlog.size();

	if (theSize > 0)
	{
#if defined(XALAN_OLD_STYLE_CASTS)
		write((const char*)&theProlog[0], theProlog.size());
#else
		write(reinterpret_cast<const char*>(&theProlog[0]), theProlog.size());
#endif
	}
}

void
XalanOutputStream::flushBuffer()
{
	if (m_buffer.size() > 0)
	{
		m_buffer.push_back(0);

		doWrite(&*m_buffer.begin());

		m_buffer.clear();
	}
}

void
XalanOutputStream::doWrite(const XalanDOMChar*	theBuffer)
{
	assert(theBuffer != 0);

	try
	{
		if (m_writeAsUTF16 == true)
		{
			assert(sizeof(XalanDOMChar) == sizeof(char) * 2);

			// This is a hack to write UTF-16 through as if it
			// were just chars.  Saves lots of time "transcoding."
#if defined(XALAN_OLD_STYLE_CASTS)
			writeData((const char*)theBuffer, length(theBuffer) * 2);
#else
			writeData(reinterpret_cast<const char*>(theBuffer), length(theBuffer) * 2);
#endif
		}
		else
		{
			transcode(theBuffer, m_transcodingBuffer);

			assert(&m_transcodingBuffer[0] != 0);

			writeData(&m_transcodingBuffer[0],
					  m_transcodingBuffer.size());
		}
	}
	catch(const XalanOutputStreamException&)
	{
		// Have to catch this error and flush any output remaining...
		m_buffer.clear();

		throw;
	}
}

void
XalanOutputStream::doWrite(
			const XalanDOMChar*		theBuffer,
			unsigned long			theBufferLength)
{
	// $$$ ToDo: Revisit this!!!
	BufferType	theLocalBuffer(theBuffer, theBuffer + theBufferLength);

	theLocalBuffer.push_back(0);

	doWrite(&theLocalBuffer[0]);
}

void
XalanOutputStream::setBufferSize(BufferType::size_type		theBufferSize)
{
	flushBuffer();

	m_bufferSize = theBufferSize;

	if (m_buffer.size() < m_bufferSize)
	{
		// Enlarge the buffer...
		m_buffer.reserve(theBufferSize + 1);
	}
	else if (m_buffer.size() > m_bufferSize)
	{
		// Shrink the buffer.

		// Create a temp buffer and make it
		// the correct size.
		BufferType	temp;

		temp.reserve(theBufferSize + 1);

		// Swap temp with m_buffer so that
		// m_buffer is now the correct size.
		temp.swap(m_buffer);
	}
}

XalanOutputStream::XalanOutputStreamException::XalanOutputStreamException(
			const XalanDOMString&	theMessage,
			const XalanDOMString&	theType) :
	XSLException(theMessage, theType)
{
}

XalanOutputStream::XalanOutputStreamException::~XalanOutputStreamException()
{
}

XalanOutputStream::UnknownEncodingException::UnknownEncodingException() :
	XalanOutputStreamException(
			TranscodeFromLocalCodePage("Unknown error occurred while transcoding!"),
			TranscodeFromLocalCodePage("UnknownEncodingException"))
{
}

XalanOutputStream::UnknownEncodingException::~UnknownEncodingException()
{
}

XalanOutputStream::UnsupportedEncodingException::UnsupportedEncodingException(const XalanDOMString&	theEncoding) :
	XalanOutputStreamException(
			TranscodeFromLocalCodePage("Unsupported encoding: ") + theEncoding,
			TranscodeFromLocalCodePage("UnsupportedEncodingException")),
	m_encoding(theEncoding)
{
}

XalanOutputStream::UnsupportedEncodingException::~UnsupportedEncodingException()
{
}

XalanOutputStream::TranscoderInternalFailureException::TranscoderInternalFailureException(const XalanDOMString&	theEncoding) :
	XalanOutputStreamException(
			TranscodeFromLocalCodePage("Unknown error occurred while transcoding to ") +
					theEncoding +
					TranscodeFromLocalCodePage("!"),
			TranscodeFromLocalCodePage("TranscoderInternalFailureException")),
	m_encoding(theEncoding)
{
}

XalanOutputStream::TranscoderInternalFailureException::~TranscoderInternalFailureException()
{
}

XalanOutputStream::TranscodingException::TranscodingException() :
	XalanOutputStreamException(
			TranscodeFromLocalCodePage("An error occurred while transcoding!"),
			TranscodeFromLocalCodePage("TranscodingException"))
{
}

XalanOutputStream::TranscodingException::~TranscodingException()
{
}
<|endoftext|>


<commit_before>//
// Copyright RIME Developers
// Distributed under the BSD License
//
// 2011-10-02 GONG Chen <chen.sst@gmail.com>
//

#include <rime/build_config.h>

#ifdef RIME_ENABLE_LOGGING
#include <glog/logging.h>
#endif  // RIME_ENABLE_LOGGING

#include <boost/filesystem.hpp>
#include <rime_api.h>
#include <rime/deployer.h>
#include <rime/module.h>
#include <rime/service.h>
#include <rime/setup.h>

namespace fs = boost::filesystem;

namespace rime {

#define Q(x) #x
RIME_API RIME_MODULE_LIST(kDefaultModules, "default" RIME_EXTRA_MODULES);
#undef Q
RIME_MODULE_LIST(kDeployerModules, "deployer");
RIME_MODULE_LIST(kLegacyModules, "legacy");

RIME_REGISTER_MODULE_GROUP(default, "core", "dict", "gears")
RIME_REGISTER_MODULE_GROUP(deployer, "core", "dict", "levers")

RIME_API void LoadModules(const char* module_names[]) {
  ModuleManager& mm(ModuleManager::instance());
  for (const char** m = module_names; *m; ++m) {
    if (RimeModule* module = mm.Find(*m)) {
      mm.LoadModule(module);
    }
  }
}

// assume member is a non-null pointer in struct *p.
#define PROVIDED(p, member) ((p) && RIME_STRUCT_HAS_MEMBER(*(p), (p)->member) && (p)->member)

RIME_API void SetupDeployer(RimeTraits *traits) {
  if (!traits) return;
  Deployer &deployer(Service::instance().deployer());
  if (PROVIDED(traits, shared_data_dir))
    deployer.shared_data_dir = traits->shared_data_dir;
  if (PROVIDED(traits, user_data_dir))
    deployer.user_data_dir = traits->user_data_dir;
  if (PROVIDED(traits, distribution_name))
    deployer.distribution_name = traits->distribution_name;
  if (PROVIDED(traits, distribution_code_name))
    deployer.distribution_code_name = traits->distribution_code_name;
  if (PROVIDED(traits, distribution_version))
    deployer.distribution_version = traits->distribution_version;
  if (PROVIDED(traits, prebuilt_data_dir))
    deployer.prebuilt_data_dir = traits->prebuilt_data_dir;
  else
    deployer.prebuilt_data_dir = (fs::path(deployer.shared_data_dir) / "build").string();
  if (PROVIDED(traits, staging_dir))
    deployer.staging_dir = traits->staging_dir;
  else
    deployer.staging_dir = (fs::path(deployer.user_data_dir) / "build").string();
}

RIME_API void SetupLogging(const char* app_name, int min_log_level, const char* log_dir) {
#ifdef RIME_ENABLE_LOGGING
  FLAGS_minloglevel = min_log_level;
  FLAGS_alsologtostderr = true;
  if (log_dir) {
    FLAGS_log_dir = log_dir;
  }
  // Do not allow other users to read/write log files created by current process.
  FLAGS_logfile_mode = 0600;
  google::InitGoogleLogging(app_name);
#endif  // RIME_ENABLE_LOGGING
}

RIME_API void SetupLogging(const char* app_name) {
  SetupLogging(app_name, 0, NULL);
}

}  // namespace rime
<commit_msg>fix(setup): avoid glog log macros conflict with macros of Windows<commit_after>//
// Copyright RIME Developers
// Distributed under the BSD License
//
// 2011-10-02 GONG Chen <chen.sst@gmail.com>
//

#include <rime/build_config.h>

#ifdef RIME_ENABLE_LOGGING
#ifdef _WIN32
#define GLOG_NO_ABBREVIATED_SEVERITIES
#endif // _WIN32
#include <glog/logging.h>
#endif  // RIME_ENABLE_LOGGING

#include <boost/filesystem.hpp>
#include <rime_api.h>
#include <rime/deployer.h>
#include <rime/module.h>
#include <rime/service.h>
#include <rime/setup.h>

namespace fs = boost::filesystem;

namespace rime {

#define Q(x) #x
RIME_API RIME_MODULE_LIST(kDefaultModules, "default" RIME_EXTRA_MODULES);
#undef Q
RIME_MODULE_LIST(kDeployerModules, "deployer");
RIME_MODULE_LIST(kLegacyModules, "legacy");

RIME_REGISTER_MODULE_GROUP(default, "core", "dict", "gears")
RIME_REGISTER_MODULE_GROUP(deployer, "core", "dict", "levers")

RIME_API void LoadModules(const char* module_names[]) {
  ModuleManager& mm(ModuleManager::instance());
  for (const char** m = module_names; *m; ++m) {
    if (RimeModule* module = mm.Find(*m)) {
      mm.LoadModule(module);
    }
  }
}

// assume member is a non-null pointer in struct *p.
#define PROVIDED(p, member) ((p) && RIME_STRUCT_HAS_MEMBER(*(p), (p)->member) && (p)->member)

RIME_API void SetupDeployer(RimeTraits *traits) {
  if (!traits) return;
  Deployer &deployer(Service::instance().deployer());
  if (PROVIDED(traits, shared_data_dir))
    deployer.shared_data_dir = traits->shared_data_dir;
  if (PROVIDED(traits, user_data_dir))
    deployer.user_data_dir = traits->user_data_dir;
  if (PROVIDED(traits, distribution_name))
    deployer.distribution_name = traits->distribution_name;
  if (PROVIDED(traits, distribution_code_name))
    deployer.distribution_code_name = traits->distribution_code_name;
  if (PROVIDED(traits, distribution_version))
    deployer.distribution_version = traits->distribution_version;
  if (PROVIDED(traits, prebuilt_data_dir))
    deployer.prebuilt_data_dir = traits->prebuilt_data_dir;
  else
    deployer.prebuilt_data_dir = (fs::path(deployer.shared_data_dir) / "build").string();
  if (PROVIDED(traits, staging_dir))
    deployer.staging_dir = traits->staging_dir;
  else
    deployer.staging_dir = (fs::path(deployer.user_data_dir) / "build").string();
}

RIME_API void SetupLogging(const char* app_name, int min_log_level, const char* log_dir) {
#ifdef RIME_ENABLE_LOGGING
  FLAGS_minloglevel = min_log_level;
  FLAGS_alsologtostderr = true;
  if (log_dir) {
    FLAGS_log_dir = log_dir;
  }
  // Do not allow other users to read/write log files created by current process.
  FLAGS_logfile_mode = 0600;
  google::InitGoogleLogging(app_name);
#endif  // RIME_ENABLE_LOGGING
}

RIME_API void SetupLogging(const char* app_name) {
  SetupLogging(app_name, 0, NULL);
}

}  // namespace rime
<|endoftext|>


<commit_before>#include <iostream>
#include <unistd.h>
#include <mutex>

#include "dasynq.h"

using namespace dasynq;

using Loop_t = EventLoop<std::mutex>;

class MySignalWatcher : public Loop_t::SignalWatcher
{
    Rearm received(Loop_t & eloop, int signo, SigInfo_p siginfo) override
    {
        using namespace std;
        cout << "Got signal: " << signo << endl;
        return Rearm::REARM;
    }
};

class MyTimer : public Loop_t::Timer
{
    Rearm timerExpiry(Loop_t & eloop, int expiry_count)
    {
        using namespace std;
        cout << "Got timeout!" << endl;
        return Rearm::REMOVE;
    }
};

int main(int argc, char **argv)
{
    Loop_t eloop;

    // block USR1 / USR2 reception
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGUSR1);
    sigaddset(&set, SIGUSR2);
    sigprocmask(SIG_BLOCK, &set, NULL);

    MySignalWatcher mse1, mse2;
    mse1.addWatch(eloop, SIGUSR1);
    mse2.addWatch(eloop, SIGUSR2);

    MyTimer mt1;
    mt1.addTimer(eloop);
    struct timespec timeout {3, 0};
    mt1.armTimerRel(eloop, timeout);

    MyTimer mt2;
    mt2.addTimer(eloop);
    timeout = {4, 0};
    mt2.armTimerRel(eloop, timeout);

    sleep(1);

    std::cout << "Running eloop..." << std::endl;
    eloop.run();
    //std::cout << "Running eloop..." << std::endl;
    eloop.run();
    //std::cout << "Running eloop..." << std::endl;
    eloop.run();

    return 0;
}
<commit_msg>Update example to match recent API changes.<commit_after>#include <iostream>
#include <unistd.h>
#include <mutex>

#include "dasynq.h"

using namespace dasynq;

using Loop_t = event_loop<std::mutex>;

class MySignalWatcher : public Loop_t::SignalWatcher
{
    rearm received(Loop_t & eloop, int signo, SigInfo_p siginfo) override
    {
        using namespace std;
        cout << "Got signal: " << signo << endl;
        return rearm::REARM;
    }
};

class MyTimer : public Loop_t::Timer
{
    rearm timerExpiry(Loop_t & eloop, int expiry_count)
    {
        using namespace std;
        cout << "Got timeout!" << endl;
        return rearm::REMOVE;
    }
};

int main(int argc, char **argv)
{
    Loop_t eloop;

    // block USR1 / USR2 reception
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGUSR1);
    sigaddset(&set, SIGUSR2);
    sigprocmask(SIG_BLOCK, &set, NULL);

    MySignalWatcher mse1, mse2;
    mse1.addWatch(eloop, SIGUSR1);
    mse2.addWatch(eloop, SIGUSR2);

    MyTimer mt1;
    mt1.addTimer(eloop);
    struct timespec timeout {3, 0};
    mt1.armTimerRel(eloop, timeout);

    MyTimer mt2;
    mt2.addTimer(eloop);
    timeout = {4, 0};
    mt2.armTimerRel(eloop, timeout);

    sleep(1);

    std::cout << "Running eloop..." << std::endl;
    eloop.run();
    //std::cout << "Running eloop..." << std::endl;
    eloop.run();
    //std::cout << "Running eloop..." << std::endl;
    eloop.run();

    return 0;
}
<|endoftext|>