#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
const unsigned int FIBOLIMIT = 1000000007;
unsigned long long getFibo(map<unsigned long long, unsigned long long>& fibo, unsigned long long n)
{
unsigned long long half = (unsigned long long)(n / 2);
auto index = fibo.find(n);
if (index != fibo.end())
{
return index->second;
}
else
{
unsigned long long a = (getFibo(fibo, half + 1) % FIBOLIMIT);
unsigned long long b = (getFibo(fibo, n - half) % FIBOLIMIT);
unsigned long long c = (getFibo(fibo, half) % FIBOLIMIT);
unsigned long long d = (getFibo(fibo, n - half - 1) % FIBOLIMIT);
fibo.insert(make_pair(n, (a * b + c * d) % FIBOLIMIT));
return fibo[n];
}
}
int main()
{
unsigned long long n;
map<unsigned long long, unsigned long long> fibo;
fibo.insert(make_pair(0, 0));
fibo.insert(make_pair(1, 1));
fibo.insert(make_pair(2, 1));
cin >> n;
cout << getFibo(fibo, n) << endl;;
return 0;
}
// The main function is only used to initialize our IFrameworkView class.
[Platform::MTAThread]
int main(Platform::Array<Platform::String^>^)
{
auto direct3DApplicationSource = ref new Direct3DApplicationSource();
CoreApplication::Run(direct3DApplicationSource);
return 0;
}
App.cpp 파일 안에 선언되어 있는 main 함수다.
그런데 우리가 알던 main 함수와 많이 다르다.
main 함수 앞에 처음 보는 선언도 있고, main 함수가 받는 parameter도, 그 형식도 낯설다.
이는 UWP(Universal Windows Platform)에서 사용하는 C++/CX의 문법으로,
지금 여기서는 자세하게 설명하지 않을 것이다.
main 함수안에서는 Direct3DApplicationSource의 reference Object를 생성하고, CoreApplication에서 Run 함수에 parameter로 넘겨주면서 Run 함수를 선언하고 있다.
App의 생성자는 m_windowClosed와 m_windowVisible 값을 초기화 해주고 있다.
이 생성자를 생성된 창이 열려 있고 화면 상에 표시가 되게 설정을 해주는 것 같다.
직접 창을 생성한다고 하지 않은 이유는 그 기능을 Initialize에서 해주고 있기 때문이다.
// The first method called when the IFrameworkView is being created.
void App::Initialize(CoreApplicationView^ applicationView)
{
// Register event handlers for app lifecycle. This example includes Activated, so that we
// can make the CoreWindow active and start rendering on the window.
applicationView->Activated +=
ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &App::OnActivated);
CoreApplication::Suspending +=
ref new EventHandler<SuspendingEventArgs^>(this, &App::OnSuspending);
CoreApplication::Resuming +=
ref new EventHandler<Platform::Object^>(this, &App::OnResuming);
}
이 함수는 IFrameworkView가 생성 될 때 가장 먼저 호출이 된다.
내부적으로는 Application의 LifeCycle과 관련된 Event Handling이 이루어진다.
물론 여기서 사용되는 Event들도 App 안에서 선언을 해두고 있다.
void App::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{
// Run() won't start until the CoreWindow is activated.
CoreWindow::GetForCurrentThread()->Activate();
}
void App::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
// Save app state asynchronously after requesting a deferral. Holding a deferral
// indicates that the application is busy performing suspending operations. Be
// aware that a deferral may not be held indefinitely. After about five seconds,
// the app will be forced to exit.
SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
create_task([this, deferral]()
{
m_main->OnSuspending();
deferral->Complete();
});
}
void App::OnResuming(Platform::Object^ sender, Platform::Object^ args)
{
// Restore any data or state that was unloaded on suspend. By default, data
// and state are persisted when resuming from suspend. Note that this event
// does not occur if the app was previously terminated.
m_main->OnResuming();
}
이 3가지는 선언, 중지, 재시작 시 호출되는 Event 함수들이다.
OnActivated는 현재 활성화 된 thread의 CoreWindow Instance 활성화 한다.
UWP에서 제공하는 함수로, 화면에 window를 표시 할 때 호출한다.
또한 Run 함수가 동작하기 위해서는 CoreWindow가 반드시 Activate 되어야 하기에, OnActivated에서 선언한다.
// Window event handlers.
void App::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
{
GetDeviceResources()->SetLogicalSize(Size(sender->Bounds.Width, sender->Bounds.Height));
m_main->OnWindowSizeChanged();
}
void App::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
{
m_windowVisible = args->Visible;
}
void App::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
{
m_windowClosed = true;
}
// DisplayInformation event handlers.
void App::OnDpiChanged(DisplayInformation^ sender, Object^ args)
{
// Note: The value for LogicalDpi retrieved here may not match the effective DPI of the app
// if it is being scaled for high resolution devices. Once the DPI is set on DeviceResources,
// you should always retrieve it using the GetDpi method.
// See DeviceResources.cpp for more details.
GetDeviceResources()->SetDpi(sender->LogicalDpi);
m_main->OnWindowSizeChanged();
}
void App::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
{
GetDeviceResources()->SetCurrentOrientation(sender->CurrentOrientation);
m_main->OnWindowSizeChanged();
}
void App::OnDisplayContentsInvalidated(DisplayInformation^ sender, Object^ args)
{
GetDeviceResources()->ValidateDevice();
}
이 Event 안의 함수들은 모두 DeviceResources에서 선언된 것들을 사용하고 있다.
그렇기에 지금은 각 Event 함수 이름을 보고 기능을 유추하는 것으로 넘어가면 될 것이다.
Load는 Run 함수가 호출 되기 전 외부 리소스들을 불러오거나, 활성화 하는 함수이다.
여기서는 App이 가지고 있는 ExampleCreationMain object인 m_main이 선언되어 있지 않을 때 새 object를 채워넣어준다.
// Initializes scene resources, or loads a previously saved app state.
void App::Load(Platform::String^ entryPoint)
{
if (m_main == nullptr)
{
m_main = std::unique_ptr<ExampleCreationMain>(new ExampleCreationMain());
}
}
대망의 Run 함수다. 이 함수는 window가 활성화 된 이후에 호출이 된다.
// This method is called after the window becomes active.
void App::Run()
{
while (!m_windowClosed)
{
if (m_windowVisible)
{
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
auto commandQueue = GetDeviceResources()->GetCommandQueue();
PIXBeginEvent(commandQueue, 0, L"Update");
{
m_main->Update();
}
PIXEndEvent(commandQueue);
PIXBeginEvent(commandQueue, 0, L"Render");
{
if (m_main->Render())
{
GetDeviceResources()->Present();
}
}
PIXEndEvent(commandQueue);
}
else
{
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
}
순서대로 살펴보자.
ProcessEvents는 dispatcher에게 input event queue에 있는 event들을 실행시키는 함수이다.
parameter로 받는 CoreProcessEventsOption은 몇 개의 event들을 실행시킬지를 나타낸다.